Próbuję zrozumieć różnicę między __getattr__
a __getattribute__
jednak jestem braku na niego.
Odpowiedź na pytanie przepełnienie stosu Różnica między __getattr__
VS__getattribute__
mówi:
__getattribute__
jest wywoływany przed spojrzeniem na rzeczywiste atrybuty obiektu, więc może być trudny do prawidłowego wdrożenia. Bardzo łatwo możesz skończyć w nieskończonych rekurencjach.
Nie mam pojęcia, co to znaczy.
Następnie mówi:
Prawie na pewno chcesz
__getattr__
.
Czemu?
Czytam, że jeśli się __getattribute__
nie powiedzie, __getattr__
to się nazywa. Dlaczego więc dwie różne metody robią to samo? Jeśli mój kod implementuje nowe klasy stylów, czego powinienem użyć?
Szukam kilku przykładów kodu, aby wyjaśnić to pytanie. Zrobiłem wszystko, co w mojej mocy, ale odpowiedzi, które znalazłem, nie omawiają dokładnie problemu.
Jeśli jest jakaś dokumentacja, jestem gotów ją przeczytać.
źródło
Odpowiedzi:
Najpierw podstawy.
W przypadku obiektów musisz poradzić sobie z ich atrybutami. Zwykle tak robimy
instance.attribute
. Czasami potrzebujemy większej kontroli (gdy nie znamy wcześniej nazwy atrybutu).Na przykład
instance.attribute
stałby sięgetattr(instance, attribute_name)
. Za pomocą tego modelu możemy uzyskać atrybut, podając nazwę atrybutu jako ciąg.Zastosowanie
__getattr__
Możesz także powiedzieć klasie, jak postępować z atrybutami, którymi nie zarządza, i zrobić to za pomocą
__getattr__
metody.Python wywoła tę metodę za każdym razem, gdy zażądasz atrybutu, który nie został jeszcze zdefiniowany, więc możesz zdefiniować, co z nim zrobić.
Klasyczny przypadek użycia:
Ostrzeżenia i wykorzystanie
__getattribute__
Jeśli chcesz złapać każdy atrybut, niezależnie od tego, czy istnieje , użyj go
__getattribute__
. Różnica polega na tym, że__getattr__
wywoływane są tylko atrybuty, które tak naprawdę nie istnieją. Jeśli ustawisz atrybut bezpośrednio, odwołanie się do tego atrybutu spowoduje jego odzyskanie bez wywoływania__getattr__
.__getattribute__
nazywa się cały czas.źródło
getattr(instance, attribute_name)
.”. Nie powinno tak być__getattribute__(instance, attribute_name)
?getattr
to wbudowana funkcja.getattr(foo, 'bar')
jest równoważne zfoo.bar
.__getattr__
jest wywoływany tylko wtedy, gdy jest zdefiniowany, ponieważ nie jest dziedziczonyobject
__getattribute__
jest wywoływany za każdym razem, gdy nastąpi dostęp do atrybutu.Spowoduje to nieskończoną rekurencję. Sprawcą jest tutaj linia
return self.__dict__[attr]
. Udawajmy (jest wystarczająco blisko prawdy), że wszystkie atrybuty są przechowywaneself.__dict__
i dostępne według ich nazw. Liniapróbuje uzyskać dostęp do
a
atrybutuf
. To wzywaf.__getattribute__('a')
.__getattribute__
następnie próbuje załadowaćself.__dict__
.__dict__
jest atrybutem,self == f
dlatego wywołania w języku Python,f.__getattribute__('__dict__')
które ponownie próbują uzyskać dostęp do atrybutu'__dict__
”. To jest nieskończona rekurencja.Jeśli
__getattr__
zamiast tego został użytyf
maa
atrybut.f.b
), nie zostałby wywołany w celu znalezienia,__dict__
ponieważ już tam__getattr__
jest i jest wywoływany tylko wtedy, gdy wszystkie inne metody znalezienia atrybutu zawiodły .„Prawidłowym” sposobem na napisanie powyższej klasy
__getattribute__
jestsuper(Foo, self).__getattribute__(attr)
wiąże__getattribute__
metodę „najbliższej” nadklasy (formalnie następnej klasy w klasie klasy Resolution Resolution Order lub MRO) z bieżącym obiektem,self
a następnie wywołuje ją i pozwala na wykonanie tej pracy.Wszystkich tych problemów można uniknąć, używając
__getattr__
Pythona, który robi to normalnie, dopóki nie zostanie znaleziony atrybut. W tym momencie Python przekazuje kontrolę nad twoją__getattr__
metodą i pozwala jej coś wymyślić.Warto również zauważyć, że możesz spotkać się z nieskończoną rekurencją
__getattr__
.Zostawię to jako ćwiczenie.
źródło
Myślę, że inne odpowiedzi wykonali wspaniałą pracę wyjaśniając różnicę pomiędzy
__getattr__
a__getattribute__
, ale jedna rzecz, która może nie być jasne, dlaczego chcesz używać__getattribute__
. Fajną rzeczą__getattribute__
jest to, że zasadniczo pozwala na przeciążenie kropki podczas uzyskiwania dostępu do klasy. Pozwala to dostosować sposób dostępu do atrybutów na niskim poziomie. Załóżmy na przykład, że chcę zdefiniować klasę, w której wszystkie metody pobierające tylko argument własny są traktowane jako właściwości:I z interaktywnego tłumacza:
Oczywiście jest to głupi przykład i prawdopodobnie nigdy nie chciałbyś tego zrobić, ale pokazuje on moc, którą można uzyskać z zastąpienia
__getattribute__
.źródło
Przeszedłem doskonałe wyjaśnienie innych. Znalazłem jednak prostą odpowiedź z tego bloga Python Magic Methods and
__getattr__
. Stamtąd pochodzą wszystkie następujące elementy.Za pomocą
__getattr__
metody magicznej możemy przechwycić to nieistniejące wyszukiwanie atrybutów i zrobić coś, aby nie zawiodło:Ale jeśli atrybut istnieje,
__getattr__
nie zostanie wywołany:__getattribute__
jest podobny do__getattr__
, z tą ważną różnicą, że__getattribute__
przechwyci KAŻDE wyszukiwanie atrybutu, nie ma znaczenia, czy atrybut istnieje, czy nie.W tym przykładzie
d
obiekt ma już wartość atrybutu. Ale kiedy próbujemy uzyskać do niego dostęp, nie otrzymujemy oryginalnej oczekiwanej wartości („Python”); otrzymujemy tylko to, co__getattribute__
wróci. Oznacza to, że praktycznie straciliśmy atrybut wartości; stało się „nieosiągalne”.źródło