160 votes

Pourquoi la magie super () de Python 3.x?

En Python 3.x, super() peut être appelée sans arguments:

class A(object):
    def x(self):
         print("Hey now")

class B(A):
    def x(self):
        super().x()
>>> B().x()
Hey now

Afin de rendre ce travail, certains au moment de la compilation de la magie est effectuée, l'une des conséquences est que le code suivant (qui relie super de super_) échoue:

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

Pourquoi est - super() parvenez pas à résoudre la super-classe à l'exécution sans l'aide du compilateur? Existe-il des situations dans lesquelles ce comportement, ou la raison sous-jacente pour elle, pourrait mordre un imprudents programmeur?

... et, comme un côté de la question: existe-t-il d'autres exemples en Python de fonctions, méthodes, etc. qui peut être interrompue par une nouvelle liaison vers un autre nom?

223voto

Martijn Pieters Points 271458

La nouvelle magie super() comportement a été ajouté pour éviter de violer les DRY (Don't Repeat Yourself), principe, voir PEP 3135. Ayant explicitement le nom de la classe par référence mondiale est aussi sujette à la même reliaison des questions que vous avez découvert avec super() lui-même:

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

Spam = Foo
Foo = something_else()

La même chose s'applique à l'aide de la classe décorateurs où le décorateur renvoie un nouvel objet, qui relie le nom de la classe:

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

La magie super() __class__ de cellules élude ces questions gentiment en vous donnant accès à la classe d'origine de l'objet.

Le PEP a été lancé par Guido, qui initialement envisagé super devenir un mot-clé, et l'idée d'utiliser une cellule à regarder jusqu'à la classe actuelle était aussi son. Certes, l'idée d'en faire un mot-clé a été le cadre de la première ébauche de la PEP.

Cependant, il était, en fait, Guido lui-même qui ensuite s'écarta de l'idée de mot clé est trop "magique', en proposant la mise en œuvre actuelle à la place. Il a prévu que l'utilisation d'un nom différent pour super() pourrait être un problème:

Mon patch utilise une solution intermédiaire: elle suppose que vous avez besoin d' __class__ chaque fois que vous utilisez une variable nommée 'super'. Ainsi, si vous (dans le monde) renommer super de supper et l'utilisation supper mais pas super, ça ne marchera pas sans arguments (mais il faudra encore travailler si vous passer soit __class__ ou de la classe réelle de l'objet); si vous avez une autre variable nommée super, les choses vont fonctionner, mais la méthode utilise la légèrement plus lent appel de chemin d'accès utilisé pour les cellules variables.

Donc, à la fin, il a été Guido lui-même qui a proclamé que l'utilisation d'un super mot-clé ne se sentait pas bien, et que la fourniture d'une magie __class__ cellule était un compromis acceptable.

Je suis d'accord que la magie, implicite comportement de la mise en œuvre est un peu surprenant, mais super() est l'un des plus mal appliquée fonctions dans la langue. Il suffit de prendre un coup d'oeil à tous les mal appliqué super(type(self), self) ou super(self.__class__, self) invocations trouvé sur Internet; si ce code n'a jamais été appelé à partir d'une classe dérivée de vous finirais avec une récurrence infinie exception. À tout le moins l'simplifié super() appel, sans arguments, évite que le problème.

Comme pour le renommé super_; il suffit de référence __class__ dans votre méthode, en tant que bien , et il va fonctionner à nouveau. La cellule est créé si vous utilisez super() ou utiliser __class__ dans votre méthode:

>>> 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X