Varsayılan davranışı bozmadan Python'daki __getattr__'yi nasıl geçersiz kılabilirim?


186

__getattr__Süslü bir şey yapmak için bir sınıfta yöntemi geçersiz kılmak istiyorum ama varsayılan davranışı kırmak istemiyorum.

Bunu yapmanın doğru yolu nedir?


20
"Break" soruyor, "değiştir" değil. Bu yeterince açık: "süslü" özellikler, yerleşik özelliklere müdahale etmemeli ve onlar gibi olabildiğince davranmalıdır. Michael'ın yanıtı hem doğru hem de yararlı.
olooney

Yanıtlar:


268

Geçersiz kılma iyi __getattr__olmalıdır - __getattr__yalnızca son çare olarak adlandırılır; örn., Adla eşleşen hiçbir öznitelik yoksa. Örneğin, erişirseniz foo.bar, __getattr__yalnızca foohiçbir özniteliği yoksa çağrılacaktır bar. Özellik işlemek istemediğiniz bir özellikse AttributeError:

class Foo(object):
    def __getattr__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            raise AttributeError

Ancak, aksine __getattr__, __getattribute__ilk olarak adlandırılacaktır (sadece yeni stil sınıfları için çalışır, yani nesneden miras alanlar). Bu durumda, varsayılan davranışı aşağıdaki gibi koruyabilirsiniz:

class Foo(object):
    def __getattribute__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            return object.__getattribute__(self, name)

Daha fazla bilgi için Python belgelerine bakın .


Bah, düzenlemenin cevabımda gösterdiğim şeyle aynı, +1.

12
Harika, Python süper içeri çağırmak gibi görünmüyor __getattr__- ne yapacağına dair bir fikir var mı? ( AttributeError: 'super' object has no attribute '__getattr__')
gatoatigrado

1
Kodunuzu görmeden söylemek zor ama üst sınıflarınızın hiçbiri getattr'u tanımlamıyor gibi görünüyor .
Colin vH

Bu hasattr ile de çalışır çünkü: "Bu, getattr (nesne, ad) çağrılıp bir istisna oluşturup oluşturmadığını görerek uygulanır." docs.python.org/2/library/functions.html#hasattr
ShaBANG

1
-1 Bu , varsayılan davranışı değiştirir. Artık AttributeErroristisna argümanlarında özniteliğin bağlamı olmayan bir var .
wim

34
class A(object):
    def __init__(self):
        self.a = 42

    def __getattr__(self, attr):
        if attr in ["b", "c"]:
            return 42
        raise AttributeError("%r object has no attribute %r" %
                             (self.__class__.__name__, attr))

>>> a = A()
>>> a.a
42
>>> a.b
42
>>> a.missing
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __getattr__
AttributeError: 'A' object has no attribute 'missing'
>>> hasattr(a, "b")
True
>>> hasattr(a, "missing")
False

Bunun için teşekkürler. Sadece kaynakta kazmadan varsayılan mesajın doğru olduğundan emin olmak istedim.
ShawnFumo

4
Sınıfın geçersiz kılınması durumunda self.__class__.__name__bunun yerine kullanılması gerektiğini düşünüyorumself.__class____repr__
Michael Scott Cuthbert

3
Bu, kabul edilen yanıttan daha iyidir, ancak ifadede değişiklik yapılması veya gelecekte istisna nesnesine ekstra bağlam eklenmesi durumunda, kodu yeniden yazmamak ve potansiyel olarak yukarı akış değişikliklerini kaçırmamak iyi olurdu.
wim

14

Michael yanıtını genişletmek için, kullanarak varsayılan davranışı korumak istiyorsanız __getattr__, bunu şu şekilde yapabilirsiniz:

class Foo(object):
    def __getattr__(self, name):
        if name == 'something':
            return 42

        # Default behaviour
        return self.__getattribute__(name)

Şimdi istisna mesajı daha açıklayıcı:

>>> foo.something
42
>>> foo.error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __getattr__
AttributeError: 'Foo' object has no attribute 'error'

2
@ fed.pavlo emin misin? Belki karıştırdın __getattr__ve __getattribute__?
José Luis

benim hatam. Kendinden farklı bir yönteme olan çağrıyı kaçırdım. ; (
fed.pavlo

2
Nitekim @ Michael'ın cevabı bu cevap olmadan tamamlanmamıştır
Grijesh Chauhan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.