質問

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

これは、Pythonがdo_something()をBのインスタンスで呼び出すべきだと言って不可能だと言っていることです。

役に立ちましたか?

解決

テキストは、詳細ではなく、アイデアのフレーバーにより読まなければならない場合があります。これはそのようなケースの1つです。

リンクページの例2.5 、2.6および2.7はすべて1つのメソッド do_your_stuff を使用する必要があります。 (つまり、 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)は、クラスメソッドを作成する古い方法です。 新しい(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が発生します:Pythonオブジェクトの呼び出し中に最大再帰深度を超えました。

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では、 super super(B、cls) super()に置き換えることができるようにcode> が追加され、Python3は super( )は、 class B の定義で 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'>

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)

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

気にしない場合、クラスメソッドが間違っている場合は修正してください(現在、完全に理解しようとしています):


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

この図が示すことを願っています。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top