Python 3.xでは、 super()
を引数なしで呼び出すことができます。
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()
がコンパイラの支援なしに実行時にスーパークラスを解決できないのはなぜですか?この振る舞い、またはその根本的な理由が不注意なプログラマーを噛む可能性のある実用的な状況はありますか?
...そして、副次的な質問として:Pythonの関数、メソッドなどの別の例はありますか?
D.R.Yへの違反を回避するために、新しいマジックsuper()
動作が追加されました。 (自分自身を繰り返さないでください)原則、 PEP 3135 を参照してください。クラスをグローバルとして参照することで明示的に名前を付ける必要があることも、super()
自体で発見した同じ再バインドの問題になりやすいです。
class Foo(Bar):
def baz(self):
return super(Foo, self).baz() + 42
Spam = Foo
Foo = something_else()
Spam().baz() # liable to blow up
同じことは、デコレータがクラス名を再バインドする新しいオブジェクトを返すクラスデコレータの使用にも当てはまります。
@class_decorator_returning_new_class
class Foo(Bar):
def baz(self):
# Now `Foo` is a *different class*
return super(Foo, self).baz() + 42
魔法のsuper()
__class__
セルは、元のクラスオブジェクトにアクセスできるようにすることで、これらの問題をうまく回避します。
PEPは 最初はsuper
がキーワードになることを想定していた と、現在のクラスを検索するためにセルを使用するというアイデア も彼の によって開始されました。確かに、キーワードにするというアイデアは PEPの最初のドラフト の一部でした。
ただし、実際には 'too magical'としてキーワードのアイデアから離れました が実際にGuido自身であり、代わりに現在の実装を提案しました。彼は super()
に別の名前を使用すると問題になる可能性があると予想していました :
私のパッチは中間ソリューションを使用します。
__class__
という名前の変数を使用するときは常に'super'
が必要であると想定しています。したがって、(グローバルに)super
の名前をsupper
に変更し、supper
ではなくsuper
を使用すると、引数なしでは機能しません(ただし、__class__
または実際のクラスオブジェクト);super
という名前の無関係な変数がある場合は動作しますが、メソッドはセル変数に使用される少し遅い呼び出しパスを使用します。
そのため、最終的には、super
キーワードを使用することは正しくないと感じ、マジック__class__
セルを提供することは許容できる妥協であると宣言したのはGuido自身でした。
実装の魔法のような暗黙の動作はやや驚くべきことですが、super()
はこの言語で最も誤って適用された関数の1つです。インターネット上で見つかった super(type(self), self)
または super(self.__class__, self)
の呼び出しをすべて見てください。そのコードのいずれかが派生クラスから呼び出された場合 あなたは無限再帰例外になります 。少なくとも、引数なしの単純化されたsuper()
呼び出しは、that問題を回避します。
名前が変更されたsuper_
;メソッド内の__class__
を参照するだけで、再び機能します。メソッドでsuper
or__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