W Pythonie 3.x super()
można wywołać bez argumentów:
class A(object):
def x(self):
print("Hey now")
class B(A):
def x(self):
super().x()
>>> B().x()
Hey now
Aby to zadziałało, wykonywana jest pewna magia w czasie kompilacji, której jedną z konsekwencji jest to, że następujący kod (który ponownie super
się wiąże super_
) zawodzi:
super_ = super
class A(object):
def x(self):
print("No flipping")
class B(A):
def x(self):
super_().x()
>>> B().x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in x
RuntimeError: super(): __class__ cell not found
Dlaczego super()
nie można rozwiązać nadklasy w czasie wykonywania bez pomocy kompilatora? Czy istnieją praktyczne sytuacje, w których takie zachowanie lub jego przyczyna mogą ugryźć nieostrożnego programistę?
... i na marginesie: czy w Pythonie są jakieś inne przykłady funkcji, metod itp., które można zepsuć, przywiązując je do innej nazwy?
python
python-3.x
super
Zero Piraeus
źródło
źródło
Odpowiedzi:
super()
Dodano nowe magiczne zachowanie, aby uniknąć naruszenia zasady SUCHY (nie powtarzaj się), patrz PEP 3135 . Konieczność jawnego nazwania klasy przez odwołanie się do niej jako globalnej jest również podatna na te same problemy z ponownym wiązaniem, które odkryłeś zsuper()
samą sobą:To samo dotyczy używania dekoratorów klas, w których dekorator zwraca nowy obiekt, który ponownie wiąże nazwę klasy:
Magiczna
super()
__class__
komórka ładnie omija te problemy, dając ci dostęp do oryginalnego obiektu klasy.PEP został zapoczątkowany przez Guido, który początkowo wyobrażał sobie, że
super
zostanie słowem kluczowym , a pomysł wykorzystania komórki do wyszukania aktualnej klasy był również jego . Z pewnością pomysł uczynienia go słowem kluczowym był częścią pierwszego projektu PEP .Jednak w rzeczywistości to sam Guido odszedł od pomysłu słowa kluczowego jako „zbyt magiczny” , proponując zamiast tego obecną implementację. On Przewiduje się, że przy użyciu innej nazwy
super()
może być problem :W końcu to sam Guido ogłosił, że użycie
super
słowa kluczowego nie wydaje się właściwe, a zapewnienie magicznej__class__
komórki jest akceptowalnym kompromisem.Zgadzam się, że magiczne, ukryte zachowanie implementacji jest nieco zaskakujące, ale
super()
jest jedną z najczęściej niewłaściwie stosowanych funkcji w języku. Wystarczy spojrzeć na wszystkie niewłaściwie zastosowanesuper(type(self), self)
lubsuper(self.__class__, self)
inwokacje znalezione w Internecie; gdyby którykolwiek z tych kodów był kiedykolwiek wywołany z klasy pochodnej , skończyłoby się to z nieskończonym wyjątkiem rekursji . Przynajmniej uproszczonesuper()
wywołanie, bez argumentów, pozwala uniknąć tego problemu.Co do przemianowanych
super_
; wystarczy odniesienie__class__
w sposobie , jak również i to będzie działać ponownie. Komórka jest tworzona, jeśli odwołasz się do nazwysuper
lub__class__
w swojej metodzie:źródło
def super(of_class=magic __class__)
coś w rodzajuself.super(); def super(self): return self.__class__
?super()
działa bez argumentów; zajmuje się głównie tym, dlaczego istnieje.super()
, w metodzie klasy, jest równoważne zsuper(ReferenceToClassMethodIsBeingDefinedIn, self)
, gdzieReferenceToClassMethodIsBeingDefinedIn
jest określane w czasie kompilacji, dołączone do metody jako o nazwie zamknięcie__class__
isuper()
wyszuka oba elementy z wywołującej ramki w czasie wykonywania. Ale tak naprawdę nie musisz tego wszystkiego wiedzieć.super()
nigdzie nie jest to funkcja automatycznie tworzona , nie.__class__
w swojej metodzie . Użyłeś nazwysuper
w swojej funkcji. Kompilator widzi to i dodaje__class__
zamknięcie.type(self)
podaje bieżący typ, który nie jest tym samym, co typ, dla którego zdefiniowano metodę. Tak więc klasaFoo
z metodąbaz
potrzebujesuper(Foo, self).baz()
, ponieważ może być podklasaclass Ham(Foo):
, w którym momencietype(self)
jestHam
isuper(type(self), self).baz()
daje nieskończoną pętlę. Zobacz post, do którego odsyłam w mojej odpowiedzi: Czy podczas wywoływania super () w klasie pochodnej mogę przekazać self .__ class__?