Frage

Ich versuche, die super () Funktion in Python zu lernen.

Ich dachte, ich ein Verständnis davon hatte, bis ich über dieses Beispiel kam (2.6) und fand ich fest.

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

Es war nicht das, was ich erwartet hatte, wenn ich diese Zeile lesen direkt vor dem Beispiel:

Wenn wir eine Klasse-Methode verwenden, haben wir eine Instanz nicht super rufen mit. Zum Glück für uns arbeitet Super sogar mit einer Art als zweites Argument. --- Der Typ kann direkt an Super weitergegeben werden wie unten gezeigt.

Das ist genau das, was Python mir sagt, ist nicht möglich, dass do_something sagen () soll mit einer Instanz von B bezeichnet werden.

War es hilfreich?

Lösung

Manchmal haben Texte mehr für den Geschmack der Idee zu lesen, anstatt für die Details. Dies ist einer der Fälle.

In der gelinkten Seite , Beispiele 2.5 , 2.6 und 2.7 sollten alle eine Methode, do_your_stuff verwenden. (Das heißt, soll do_something zu do_your_stuff geändert werden.)

Darüber hinaus, wie Ned Deily wies darauf hin, A.do_your_stuff hat eine Klassenmethode sein.

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 gibt ein gebunden Methode (siehe Fußnote 2 ). Da cls als zweites Argument übergeben wurde, um zu super() ist es cls, die auf dem zurück Verfahren gebunden wird. Mit anderen Worten, cls wird als erstes Argument der Methode do_your_stuff() der Klasse A übergeben.

Um es zu wiederholen: super(B, cls).do_your_stuff() verursacht A der do_your_stuff Methode zu sein genannt mit cls als erstes Argument übergeben. Damit das funktioniert, A der do_your_stuff hat eine Klassenmethode sein. Die verlinkte Seite nicht erwähnt, dass, aber das ist definitiv der Fall ist.

PS. do_something = classmethod(do_something) ist der alte Weg, um eine Class zu machen. Der neue (er) Weg ist, die @classmethod Dekorateur zu verwenden.


Beachten Sie, dass super(B, cls) nicht durch super(cls, cls) ersetzt werden. Dies könnte zu Endlosschleifen führen. Zum Beispiel:

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()

wird RuntimeError: maximum recursion depth exceeded while calling a Python object erhöhen.

Wenn cls C ist, dann super(cls, cls) sucht nach der Klasse C.mro(), die nach C kommt.

In [161]: C.mro()
Out[161]: [__main__.C, __main__.B, __main__.A, object]

Da diese Klasse B ist, wenn cls C ist, super(cls, cls).do_your_stuff() immer ruft B.do_your_stuff. Da super(cls, cls).do_your_stuff() innerhalb B.do_your_stuff genannt wird, am Ende Sie B.do_your_stuff in einer Endlosschleife aufgerufen wird.

In Python3, die 0-Argument Form von super war hinzugefügt, so super(B, cls) durch super() ersetzt werden könnte, und Python3 wird aus dem Kontext heraus, die super() sein sollte als gleichwertig in der Definition von class B super(B, cls).

Aber in keinem Fall ist super(cls, cls) (oder aus ähnlichen Gründen, super(type(self), self)) immer korrekt.

Andere Tipps

In Python 3, Sie überspringen können Argumente für super Angabe

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

Ich glaube, ich den Punkt verstanden habe nun dank dieser schönen Seite und schöne Gemeinschaft.

Wenn Sie nichts dagegen mich nicht bitte korrigieren, wenn ich auf Class falsch bin (was ich jetzt zu verstehen, voll bin versucht):


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

Ich hoffe, diese Abbildung zeigt ..

scroll top