Jak przesłonić __getattr__ w Pythonie bez naruszenia domyślnego zachowania?

185

Chcę zastąpić __getattr__metodę na klasie, aby zrobić coś wymyślnego, ale nie chcę przerywać domyślnego zachowania.

Jak to zrobić w odpowiedni sposób?

płaszcze
źródło
20
„Przerwa”, pyta, a nie „zmiana”. To dość jasne: „fantazyjne” atrybuty nie powinny zakłócać wbudowanych atrybutów i powinny zachowywać się tak bardzo, jak to możliwe. Odpowiedź Michaela jest zarówno poprawna, jak i pomocna.
olooney,

Odpowiedzi:

268

Przesłanianie __getattr__powinno być w porządku - __getattr__jest wywoływane tylko w ostateczności, tj. Jeśli w instancji nie ma atrybutów pasujących do nazwy. Na przykład, jeśli uzyskasz dostęp foo.bar, __getattr__zostanie wywołany tylko wtedy, gdy nie zostanie wywołany foożaden atrybut bar. Jeśli atrybut nie jest obsługiwany, podnieś AttributeError:

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

Jednak w przeciwieństwie do __getattr__, __getattribute__zostanie wywołany jako pierwszy (działa tylko dla klas nowego stylu, tj. Dziedziczących po obiekcie). W takim przypadku możesz zachować domyślne zachowanie:

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

Zobacz dokumentację Python, aby uzyskać więcej .

Michael Williamson
źródło
Bah, twoja edycja ma to samo, co pokazywałem w mojej odpowiedzi, +1.
12
Fajnie, Python nie lubi dzwonić do super- __getattr__żadnych pomysłów, co robić? ( AttributeError: 'super' object has no attribute '__getattr__')
gatoatigrado
1
Trudno powiedzieć bez obejrzenia kodu, ale wygląda na to, że żadna z nadklas nie definiuje getattr .
Colin vH
Działa to również z hasattr, ponieważ: „Jest to realizowane przez wywołanie getattr (obiekt, nazwa) i sprawdzenie, czy zgłasza wyjątek, czy nie”. docs.python.org/2/library/functions.html#hasattr
ShaBANG
1
-1 ten sposób zmodyfikować zachowanie domyślne. Teraz masz AttributeErrorbez kontekstu atrybutu w args wyjątku.
wim