Przede wszystkim, to co się dzieje, gdy robisz with something
, to nie tylko contextlib
że patrzy specjalnej metody typu. Warto również zauważyć, że to samo dzieje się z innymi metodami specjalnymi: np. a + b
wyniki w type(a).__add__(a, b)
.
Ale dlaczego tak się dzieje? Jest to pytanie często uruchamiane na listach dyskusyjnych python-dev i python-ideas. A kiedy mówię "często", mam na myśli "bardzo często".
Ostatni z nich to: Missing Core Feature: + - */| & do not call getattr i Eliminating special method lookup.
Oto kilka interesujących punktów:
Obecne zachowanie jest zgodne z projektem - specjalne metody są wzrok, gdy gniazdach na klasę obiektu, a nie jako atrybuty instancji. Umożliwia to interpreterowi pominięcie kilku kroków w procesie wyszukiwania atrybutów o normalnej instancji .
(Source)
Warto zauważyć, że zachowanie jest jeszcze bardziej magiczne niż to. Nawet podczas wyszukiwania w klasie domyślne wyszukiwanie metody omija __getattr__
i __getattribute__
metaklasy. Tak więc wyszukiwanie specjalne w trybie specjalnym nie jest zwykłym wyszukiwaniem, które dzieje się w klasie w klasie zamiast w instancji; jest to w pełni magiczne poszukiwanie , które nie angażuje zwykłych haków dostosowywania dostępu do atrybutu na żadnym poziomie na poziomie .
(Source)
Takie zachowanie jest również udokumentowane w dokumentacji referencyjnego: Special method lookup, który mówi:
Omijanie maszyny w ten sposób __getattribute__()
zapewnia znaczące możliwości dla optymalizacji prędkości w tłumacza, w koszt pewnej elastyczności w posługiwaniu się specjalnymi metodami (specjalna metoda musi być ustawiona na samym obiekcie klasy, aby być konsekwentnie wywoływanym przez tłumacza).
W skrócie, wydajność jest głównym problemem. Ale przyjrzyjmy się temu bliżej.
Jaka jest różnica między type(obj).__enter__()
a obj.__enter__()
?
Po napisaniu obj.attr
zostaje wywołany type(obj).__getattribute__('attr')
. Domyślna implementacja __getattribute__()
wyszukuje attr
w słowniku instancji (tj. obj.__dict__
) i w przestrzeni nazw klasy, a w przeciwnym razie wywołuje type(obj).__getattr__('attr')
.
To było szybkie wyjaśnienie i pominąłem niektóre szczegóły, jednak powinno ci dać wyobrażenie o tym, jak skomplikowane może być wyszukiwanie atrybutów i jak wolno to może się stać. Zwarcie w specjalnym wyszukiwaniu metod z pewnością zapewnia poprawę wydajności, ponieważ wyszukiwanie w stylu "klasycznym" może być zbyt wolne.
Dzięki za odpowiedź. Zastanawiam się jednak, dlaczego 'type (a) .__ dodaj __ (a, b)' zamiast 'a .__ dodaj __ (b)'. Czyż nie są one takie same? – Achimnol
@Achimnol: Nie są one takie same, jeśli przypisujesz coś do 'a .__ add__'. – user2357112
@Achimnol: Wydaje mi się, że również odpowiedziałem na to pytanie, ale proszę, powiedz mi, czy byłem zbyt niejasny –