クラスメソッドでsuperを使用する


82

Pythonでsuper()関数を学習しようとしています。

この例(2.6)に出くわして行き詰まるまで、私はそれを理解していると思いました。

http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html#super-with-classmethod-example

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に渡すことができます。

これは、do_something()をBのインスタンスで呼び出す必要があると言っても、Pythonが私に言っていることではありません。


回答:


98

時々、テキストは詳細よりもアイデアの趣味のためにもっと読まなければなりません。これはそのようなケースの1つです。

ではリンク先のページ、例2.5、2.6および2.7はすべて、一つの方法を使用する必要がありますdo_your_stuff。(つまり、do_somethingに変更する必要がありますdo_your_stuff。)

加えて、ネッド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バインドされたメソッドを 返します(脚注2参照)。以来 clsの2番目の引数として渡されたsuper()、それはcls返さメソッドにバインドされることを。つまり、クラスAのclsメソッドの最初の引数として渡されますdo_your_stuff()

繰り返しますsuper(B, cls).do_your_stuff()が、最初の引数としてpassedを使用してAdo_your_stuffメソッドが呼び出されclsます。それが機能するためには、A's do_your_stuffはクラスメソッドでなければなりません。リンク先のページにはそのことは記載されていませんが、間違いなくそうです。

PS。do_something = classmethod(do_something)classmethodを作成する古い方法です。新しい(er)方法は、@ 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あるCsuper(cls, cls).do_your_stuff() 常に呼び出しますB.do_your_stuffsuper(cls, cls).do_your_stuff()は内部B.do_your_stuffで呼び出されるためB.do_your_stuff、無限ループで呼び出すことになります。

Python3では、の0引数形式superが追加されたため、super(B, cls)で置き換えることができますsuper()。Python3は、コンテキストからsuper()、の定義でclass Bsuper(B, cls)。と同等である必要があることを認識します。

しかし、いかなる状況においてもsuper(cls, cls)(または同様の理由でsuper(type(self), self))正しいことはありません。


super(cls、cls)を使用する際の落とし穴はありますか?
George Moutsopoulos 2018

2
@GeorgeMoutsopoulos:super(cls, cls)ほぼ間違いなく間違いです。理由を説明するために上記の投稿を編集しました。
unutbu 2018

37

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

この特定の質問がPython2を具体的に扱っている場合、この回答は別の質問に移される可能性があります(リンクされたWebサイトCafePyが利用できなくなったため、わかりにくいです)。
タンコボット2017年

私のプロジェクトではうまくいきません。それは与えているRuntimeError: super(): no arguments
madtyn

4

記事を少し明確にするために更新しました:Pythonの属性とメソッド#スーパー

上記のclassmethodを使用した例は、クラスメソッドが何であるかを示しています。最初のパラメーターとしてインスタンスではなくクラス自体を渡します。ただし、メソッドを呼び出すためのインスタンスも必要ありません。例:

>>> class A(object):
...     @classmethod
...     def foo(cls):
...         print cls
... 
>>> A.foo() # note this is called directly on the class
<class '__main__.A'>

2

Webページの例は、公開されたとおりに機能しているようです。do_somethingスーパークラスのメソッドも作成しましたが、クラスメソッドにはしませんでしたか?このようなものはあなたにそのエラーを与えるでしょう:

>>> class A(object):
...     def do_something(cls):
...         print cls
... #   do_something = classmethod(do_something)
... 
>>> class B(A):
...     def do_something(cls):
...         super(B, cls).do_something()
...     do_something = classmethod(do_something)
... 
>>> B().do_something()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in do_something
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)

いいえ、私のAクラスは次のようになります。classA(object):def do_your_stuff(self):print "this is A"投稿時に「classA」が必要ですか?(do_something = classmethod(do_something)を使用)?ドキュメントはこれについて何も述べていないように感じます
..– dza

1
superB do_somethingメソッドでの呼び出しの要点は、そのスーパークラスの1つでその名前のメソッドを呼び出すことです。A(またはオブジェクト)に1つがない場合、B()。do_something()呼び出しはsuper object has no attribute do_something。で失敗します。〜unutbuは、ドキュメントの例に誤りがあることを正しく指摘しています。
Ned Deily 2009年

0

この美しいサイトと素敵なコミュニティのおかげで、私は今そのポイントを理解したと思います。

よろしければ、classmethods(現在完全に理解しようとしています)が間違っている場合は訂正してください。


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

このイラストが示すことを願っています..


:クラスメソッドの説明については、おそらくあなたは、この有用見つけることができますstackoverflow.com/questions/1669445/...
unutbu
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.