2013-10-26 11 views
125

super()は、引数なしで呼び出すことができます。この作業を行うためにはPython 3.xのsuper()魔法はなぜですか? Pythonの3.xでは

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

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

は、いくつかのコンパイル時の魔法が行われ、1つの結果は、ことを次のコードです(これsuper_superを再バインド)失敗:

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 

なぜsuper() RESすることができませんコンパイラの助けを借りずに実行時にスーパークラスをolveしますか?この動作、またはその根本的な理由が不注意なプログラマーに噛み込む可能性のある実用的な状況はありますか?

...そして、別の質問として、別の名前に再バインドすることで壊れる可能性のある関数、メソッドなどのPythonの他の例がありますか?

+6

私はアーミンをもらおう(この[1]に説明を行うhttp://lucumr.pocoo.org/2010/1/7/pros-and-cons-about-python-3 /)を使用します。これはまた別の良い[投稿](http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/) –

+0

に関連しています:http://stackoverflow.com/q/36993577/674039 – wim

答えて

184

新しいマジックsuper()の動作は、D.R.Y.に違反しないように追加されました。 (あなた自身を繰り返さないでください)原則は、PEP 3135を参照してください。

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

Spam = Foo 
Foo = something_else() 

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

同じことが再バインドされ、デコレータは、新しいオブジェクトを返すクラスのデコレータの使用に適用されます。明示的にグローバルとしてそれを参照することで、クラスに名前を付けるために持つことも、あなたがsuper()自身で発見された同じ再バインドの問題を起こしやすいですクラス名:魔法super()__class__セルを使用して、元のクラスオブジェクトへのアクセスを与えることによってきれいに、これらの問題を回避し

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

PEPは、Guido(initially envisioned super becoming a keyword)によって開始され、現在のクラスwas also hisを参照するためにセルを使用するというアイディアがあります。確かに、それをキーワードにする考えはfirst draft of the PEPの一部でした。

実際にGuido自身がstepped away from the keyword idea as 'too magical'でしたが、現在の実装を代わりに提案しています。彼anticipated that using a different name for super() could be a problem

私のパッチは、中間体溶液を使用しています。それはあなたが'super'という名前の変数を使用するたびに__class__ を必要と想定しています。このように、あなたは(グローバル) suppersuperの名前を変更し、supperなくsuperが、それは引数なし を動作しません使用します(しかし、あなたがそれを渡すと、それはまだ動作するか __class__または実際のクラスオブジェクト)場合。関連性のない という変数がある場合は、何か問題はありませんが、この方法ではセル変数に使用される少し遅い呼び出しパスが使用されます( )。

だから、最後に、それは superキーワードを使用すると、右感じていなかったこと、そして魔法 __class__セルを提供することは許容できる妥協点があったことを宣言したグイド自身でした。

実装の黙示的な動作はやや驚くべきことですが、super()は、この言語で最も誤って適用されている機能の1つです。インターネット上で誤って見つかったsuper(type(self), self)またはsuper(self.__class__, self)の呼び出しを見てみましょう。そのコードのいずれかが派生クラスyou'd end up with an infinite recursion exceptionから呼び出された場合。少なくとも簡略化されたsuper()呼び出しでは、引数なしでそのの問題は回避されます。

super_と改名されました。あなたのメソッドでも__class__を参照するだけで、となり、再び動作します。あなたの方法でsuperまたは__class__名を参照いずれかの場合は、セルが作成されます。

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

良い書きかけです。しかしそれはまだ泥のようにはっきりしている。あなたは、super()が 'self.super();のような' def super(of_class = magic __class __) 'のような自動的にインスタンス化された関数と同等であると言っています。デフ・スーパー(自己):自己を返す.__クラス__? –

+12

@CharlesMerriam:この投稿は引数のない 'super()'の仕組みではありません。それは主に*なぜ*それが存在するかを扱う。コンパイル時に 'ReferenceToClassMethodIsBeingDefinedIn'が決定され、' __class__'という名前のクロージャーとしてメソッドにアタッチされ、 'super()'はクラスのメソッドで 'super()'と同等です。 'は、実行時に呼び出しフレームから両方を検索します。しかし、実際にはすべてを知る必要はありません。 –

+1

@CharlesMerriam:しかし、 'super()'は*自動的にインスタンス化された関数*に近いものではありません。 –

関連する問題