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.