Dlaczego Python 3.X ' s super() magic?

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 magia czasu kompilacji, której konsekwencją jest to, że następujący kod (który zmienia super na super_) nie działa:

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 jest w stanie rozwiązać superklasy w czasie wykonywania bez pomocy kompilatora? Czy istnieją praktyczne sytuacje, w których takie zachowanie lub jego przyczyna mogłyby ugryźć nieostrożny programista?

... i pytanie poboczne: czy w Pythonie są jakieś inne przykłady funkcji, metod itp. które można złamać zmieniając je na inne imię?

Author: Martijn Pieters, 2013-10-26

1 answers

Dodano nowe zachowanie magiczne super(), aby uniknąć naruszenia zasady D. R. Y. (nie powtarzaj się), zobacz PEP 3135 . W przeciwieństwie do innych klas, klasy te mogą być używane jako klasy globalne, ale nie mogą być używane jako klasy globalne.]}

class Foo(Bar):
    def baz(self):
        return super(Foo, self).baz() + 42

Spam = Foo
Foo = something_else()

Spam().baz()  # liable to blow up

To samo dotyczy użycia dekoratorów klasy, gdzie dekorator zwraca nowy obiekt, który ponownie zmienia nazwę klasy:

@class_decorator_returning_new_class
class Foo(Bar):
    def baz(self):
        # Now `Foo` is a *different class*
        return super(Foo, self).baz() + 42

Magia super() __class__ cell ładnie pomija te problemy przez daje Ci dostęp do oryginalnego obiektu klasy.

PEP został uruchomiony przez Guido, który początkowo zakładał, że super stanie się słowem kluczowym , a pomysł użycia komórki do znalezienia bieżącej klasy był również jego. Oczywiście, pomysł, aby to słowo kluczowe było częścią pierwszy szkic PEP.

[27]}W rzeczywistości jednak to sam Guido odszedł od idei słowa kluczowego jako "zbyt magiczny" [29]}, proponując obecną realizację zamiast tego. przewidział, że użycie innej nazwy dla super() może być problemem :

Mój patch używa rozwiązania pośredniego: zakłada, że potrzebujesz __class__ ilekroć używasz zmiennej o nazwie 'super'. Tak więc, jeśli (globalnie) Zmień nazwę super na supper i użyj supper, ale nie super, to nie zadziała bez argumentów (ale i tak będzie działać, jeśli go przekażesz albo __class__ lub rzeczywisty obiekt klasy); jeśli masz niepowiązany zmienna o nazwie super, wszystko będzie działać, ale metoda wykorzysta nieco wolniejsza ścieżka wywołania używana dla zmiennych komórki.

Ostatecznie to sam Guido stwierdził, że użycie słowa kluczowego nie jest w porządku, a dostarczenie magicznej komórki jest akceptowalnym kompromisem.

Zgadzam się, że magiczne, Ukryte zachowanie implementacji jest nieco zaskakujące, ale super() jest jedną z najbardziej błędnych funkcji w języku. Wystarczy spojrzeć na wszystkie źle stosowane super(type(self), self) lub super(self.__class__, self) wywołania Znalezione w Internecie; gdyby któryś z tych kodów został wywołany z pochodnej klasy , skończyłbyś z nieskończonym wyjątkiem rekurencyjnym. Przynajmniej uproszczone wywołanie super(), bez argumentów, unika tego problemu.

Jeśli chodzi o nazwę super_; wystarczy odwołać się __class__ w swojej metodzie , jak również i będzie działać ponownie. Komórka jest tworzona, jeśli odwołujesz się do super lub __class__ imiona w Twoim "metoda": {]}

>>> super_ = super
>>> class A(object):
...     def x(self):
...         print("No flipping")
... 
>>> class B(A):
...     def x(self):
...         __class__  # just referencing it is enough
...         super_().x()
... 
>>> B().x()
No flipping
 221
Author: Martijn Pieters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-10 18:27:45