2012-11-24 22 views
17

__getattribute__ yönteminin sonsuz döngüden kaçınılması için dikkatle yazılması gerekir. Örneğin:Python: sonsuz döngüden kaçınmak için __getattribute__

class A: 
    def __init__(self): 
     self.x = 100 

    def __getattribute__(self, x): 
     return self.x 

>>> a = A() 
>>> a.x # infinite looop 
RuntimeError: maximum recursion depth exceeded while calling a Python object 


class B: 
    def __init__(self): 
     self.x = 100 

    def __getattribute__(self, x): 
     return self.__dict__[x] 

>>> b = B() 
>>> b.x # infinite looop 
RuntimeError: maximum recursion depth exceeded while calling a Python object 

Dolayısıyla biz bu şekilde yöntem yazmak gerekir: object.__getattribute__ yöntem çalışır neden

class C: 
    def __init__(self): 
     self.x = 100 

    def __getattribute__(self, x): 
     # 1. error 
     # AttributeError: type object 'object' has no attribute '__getattr__' 
     # return object.__getattr__(self, x) 

     # 2. works 
     return object.__getattribute__(self, x) 

     # 3. works too 
     # return super().__getattribute__(x) 

Sorum şu? object nereden __getattribute__ yöntemini alır? object herhangi __getattribute__ yoksa, o zaman biz sadece sınıfın C üzerinde ama süper sınıfın aracılığıyla aynı yöntemi çağırıyor. Neden, yöntemi süper sınıf yoluyla çağırmak sonsuz bir döngüye neden olmaz?

+2

'__getattribute__' ve '__getattr__'' ye ihtiyacınız olduğundan emin misiniz? –

+4

Evet, çünkü sınıfımda TÜM öznitelik getirilerini engellemem gerekiyor. Ama yapmasam bile, bunun neden böyle olduğunu tam olarak bilmek isterim. – treecoder

+1

Peki ya * tüm * öznitelik erişimini engellemek zorunda ya da :-) –

cevap

21

__getattribute__ uygulamanızın sadece bir kanca olduğu izlenimi uyandırıyorsunuz, eğer bunu sağlarsanız Python onu arayacaksa ve aksi takdirde yorumlayıcı normal büyüyü doğrudan yapacaktır. doğru değil

. Python örneklerde özniteliklere baktığında, tüm öznitelik erişimi için __getattribute__ ana girdidir ve object varsayılan uygulamayı sağlar. Uygulamanız, orijinali'u geçersiz kılan 'dur ve uygulamanız hiçbir zaman geri dönüş öznitelikleri için alternatif yollar sağlamazsa başarısız olur. Mesela (self) için tüm özellik erişim type(self).__getattribute__(self, attr) üzerinden tekrar kanalize edilir beri kullanımı bu yöntemde erişimi bağlıyor olamaz.

bu çevrede en iyi yolu yine geçersiz kılınan orijinali arayarak olduğunu. super(C, self).__getattribute__(attr)'un geldiği yer burası; sınıf özünürlüğü sırasındaki bir sonraki sınıfı, sizin için özellik erişimini ele almak için soruyorsunuz.

Alternatif olarak, bağlanmamış object.__getattribute__() yöntemini doğrudan arayabilirsiniz. Bu yöntemin C uygulaması niteliği erişimi için son durağıdır (bu __dict__ doğrudan erişim sahiptir ve bu sayede aynı sınırlamalara bağlı değildir).

Not: super(), yöntem-çözüm sıralı temel sınıflarında bir sonraki yöntemin bulunup bulunmadığına bakacak bir proxy nesnesi döndürür. Böyle bir yöntem yoksa, bir özellik hatasıyla başarısız olur. Orijinal metodu asla asla arayacaktır. Böylece Foo.bar() bir temel sınıf uygulaması veya bir nitelik hatası, aslaFoo.bar kendisi olacak ya kadar super(Foo, self).bar görünümlü.Böyle

8

Bunu yaptığınızda:

return object.__getattribute__(self, x) 

Belirli bir işlevi aradığınız - nesne sınıfında tanımlanan bir değil A'da tanımlanan, o yüzden Yinelemesiz yoktur.

Bunu yaptığınızda:

return self.x 

sen izin veriyorsun piton işlevin çağrılacağı seçmenize ve A'dan tek tek çağırması ve sonsuz özyinelemeye var.

+0

' object' sınıfında tanımlanmış bir işlev yok. Orada tanımlanmış bir işlev varsa, o zaman 'object'' __getattr__' (# 1 hatası göstermediği gibi) tanımlayacaktır. Öyleyse neden nesne sadece '__getattribute__' yöntemini tanımlar? – treecoder

+1

@greengit: neden olmasın? 'Object' getattribute 'öğesine eriştiğimde,' object 'nesnelerinin' slot wrapper '__getattribute' 'öğesini görüyorum. –

+0

Yani 'object' sadece '__getattribte__' ve __getattr__' değil tanımlar? Bildiğim kadarıyla, “object” sınıfının tüm bu yöntemlerin uygulanması no-op. Bir yerdeysem beni düzeltin. – treecoder

2

Yaz bunu (nesne den C devralır):

class C(object): 
    def __init__(self): 
     self.x = 100 

    def __getattribute__(self, x): 
     return object.__getattribute__(self, x) 

Şimdi nesne .__ getAttribute __ (self, x) çalışır nedenini görmek - Üst nesne çağırıyor.

İlgili konular