Pythonでsuper()関数を学ぼうとしています。
この例(2.6)に出くわして自分が動けなくなるまで、私はそれを把握していると思った。
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "test.py", line 9, in do_something
do_something = classmethod(do_something)
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)
>>>
例の直前にこの行を読んだとき、私は期待していなかった:
クラスメソッドを使用している場合、superを呼び出すインスタンスはありません。幸いなことに、superは2番目の引数として型を使用しても機能します。 ---以下に示すように、タイプを直接superに渡すことができます。
これはまさにPythonは、do_something()がBのインスタンスで呼び出されるべきだと言うことでは不可能だと言っています。
場合によっては、詳細よりもアイデアのフレーバーのために、テキストをもっと読む必要があります。これはそのようなケースの1つです。
linked page では、例2.5、2.6および2.7はすべて_do_your_stuff
_という1つのメソッドを使用する必要があります。 (つまり、_do_something
_を_do_your_stuff
_に変更する必要があります。)
さらに、 Ned Deilyが指摘したように であるため、_A.do_your_stuff
_はクラスメソッドでなければなりません。
_class A(object):
@classmethod
def do_your_stuff(cls):
print 'This is A'
class B(A):
@classmethod
def do_your_stuff(cls):
super(B, cls).do_your_stuff()
B.do_your_stuff()
_
super(B, cls).do_your_stuff
はboundメソッドを返します( footnote 2 を参照)。 cls
がsuper()
の2番目の引数として渡されたため、返されたメソッドにバインドされるのはcls
です。つまり、cls
はクラスAのメソッドdo_your_stuff()
の最初の引数として渡されます。
繰り返します:super(B, cls).do_your_stuff()
は、A
の_do_your_stuff
_メソッドを、cls
を最初の引数として渡して呼び出します。それが機能するためには、A
の_do_your_stuff
_がクラスメソッドである必要があります。リンクされたページではそれについて言及されていませんが、それは間違いなく事実です。
PS。 do_something = classmethod(do_something)
は、クラスメソッドを作成する古い方法です。新しい方法は、@ classmethodデコレータを使用することです。
super(B, cls)
はsuper(cls, cls)
に置き換えることができないことに注意してください。そうすると、無限ループにつながる可能性があります。例えば、
_class A(object):
@classmethod
def do_your_stuff(cls):
print('This is A')
class B(A):
@classmethod
def do_your_stuff(cls):
print('This is B')
# super(B, cls).do_your_stuff() # CORRECT
super(cls, cls).do_your_stuff() # WRONG
class C(B):
@classmethod
def do_your_stuff(cls):
print('This is C')
# super(C, cls).do_your_stuff() # CORRECT
super(cls, cls).do_your_stuff() # WRONG
C.do_your_stuff()
_
_RuntimeError: maximum recursion depth exceeded while calling a Python object
_を発生させます。
cls
がC
の場合、super(cls, cls)
はC.mro()
でC
の後にあるクラスを検索します。
_In [161]: C.mro()
Out[161]: [__main__.C, __main__.B, __main__.A, object]
_
そのクラスはB
であるため、cls
がC
の場合、super(cls, cls).do_your_stuff()
always_B.do_your_stuff
_を呼び出します。 super(cls, cls).do_your_stuff()
は_B.do_your_stuff
_内で呼び出されるため、無限ループで_B.do_your_stuff
_を呼び出すことになります。
Python3では、 0-argument形式のsuper
が追加されたため、super(B, cls)
をsuper()
に置き換えることができ、Python3は_class B
_の定義のsuper()
はsuper(B, cls)
と同等である必要があるというコンテキスト。
ただし、super(cls, cls)
(または同様の理由でsuper(type(self), self)
)が正しいという状況はありません。
Python 3)では、super
の引数の指定をスキップできます。
class A:
@classmethod
def f(cls):
return "A's f was called."
class B(A):
@classmethod
def f(cls):
return super().f()
assert B.f() == "A's f was called."
記事を少しわかりやすくするために更新しました: Pythonの属性とメソッド#スーパー
上記のclassmethodを使用した例は、クラスメソッドとは何かを示しています-インスタンスの代わりにクラス自体を最初のパラメーターとして渡します。しかし、メソッドを呼び出すためのインスタンスさえ必要ありません、例えば:
>>> class A(object):
... @classmethod
... def foo(cls):
... print cls
...
>>> A.foo() # note this is called directly on the class
<class '__main__.A'>
この美しいサイトと素敵なコミュニティのおかげで、私は今ポイントを理解したと思います。
あなたが気にしない場合は、私がクラスメソッドについて間違っている場合は私を修正してください(今私は完全に理解しようとしています):
# EXAMPLE #1
>>> class A(object):
... def foo(cls):
... print cls
... foo = classmethod(foo)
...
>>> a = A()
>>> a.foo()
# THIS IS THE CLASS ITSELF (__class__)
class '__main__.A'
# EXAMPLE #2
# SAME AS ABOVE (With new @decorator)
>>> class A(object):
... @classmethod
... def foo(cls):
... print cls
...
>>> a = A()
>>> a.foo()
class '__main__.A'
# EXAMPLE #3
>>> class B(object):
... def foo(self):
... print self
...
>>> b = B()
>>> b.foo()
# THIS IS THE INSTANCE WITH ADDRESS (self)
__main__.B object at 0xb747a8ec
>>>
この図が示すことを願っています..