Pergunta

Eu estou tentando aprender a função super () em Python.

Eu pensei que tinha uma compreensão de que até I veio este exemplo (2.6) e encontrei-me preso.

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

Não foi o que eu esperava quando eu li esse direito linha antes o exemplo:

Se estamos usando um método de classe, não temos uma instância para chamar super com. Felizmente para nós, super funciona mesmo com um tipo como o segundo argumento. --- O tipo pode ser passado directamente para a super como mostrado abaixo.

Que é exatamente o Python me diz que não é possível, dizendo que do_something () deve ser chamado com uma instância de B.

Foi útil?

Solução

Às vezes, os textos têm de ser ler mais para o sabor da idéia em vez de para os detalhes. Este é um desses casos.

ligada página , Exemplos 2,5 , 2.6 e 2.7 devem utilizam todos um método, do_your_stuff. (Isto é, do_something deve ser alterado para do_your_stuff.)

Além disso, como Ned Deily apontou , A.do_your_stuff tem que ser um método de classe.

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 retorna um obrigado método (ver nota 2 ). Desde cls foi passado como o segundo argumento para super(), é cls que fica ligado ao método retornou. Em outras palavras, cls é passado como o primeiro argumento para o do_your_stuff() método da classe A.

Para reiterar: super(B, cls).do_your_stuff() provoca método A de do_your_stuff ser chamado com cls passado como o primeiro argumento. Para que isso funcione, de A do_your_stuff tem de ser um método de classe. A página de destino não menciona que, mas isso é definitivamente o caso.

PS. do_something = classmethod(do_something) é a velha maneira de fazer uma classmethod. A nova forma (er) é usar o decorador @classmethod.


Note que super(B, cls) não pode ser substituído por super(cls, cls). Fazer isso pode levar a loops infinitos. Por exemplo,

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

elevará RuntimeError: maximum recursion depth exceeded while calling a Python object.

Se cls é C, então pesquisas super(cls, cls) C.mro() para a classe que vem depois C.

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

Uma vez que a classe é B, quando cls é C, super(cls, cls).do_your_stuff() sempre chama B.do_your_stuff. Desde super(cls, cls).do_your_stuff() é chamado dentro B.do_your_stuff, você acaba chamando B.do_your_stuff em um loop infinito.

Em Python3, o forma 0 argumento de super foi adicionado de modo super(B, cls) poderia ser substituída por super(), e Python3 irá descobrir a partir do contexto que super() na definição de class B deve ser equivalente para super(B, cls).

Mas, em nenhuma circunstância é super(cls, cls) (ou por razões semelhantes, super(type(self), self)) sempre correta.

Outras dicas

Em Python 3, você pode pular especificar argumentos para 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."

Eu atualizei o artigo para torná-lo um pouco mais claro: Python atributos e métodos # Super

O seu exemplo usando classmethod acima mostra o que um método de classe é - ele passa a própria classe em vez da instância como o primeiro parâmetro. Mas você não precisa mesmo de uma instância para chamar o método, por exemplo:.

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

O exemplo a partir da página web parece funcionar como publicado. Você criou um método do_something para a superclasse tão bem, mas não torná-lo em um classmethod? Algo como isso vai lhe dar esse erro:

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

Eu acho que eu entendi o ponto de agora, graças a este site beatiful e encantador comunidade.

Se você não se importa por favor me corrija se eu estiver errado em classmethods (que agora estou tentando entender completamente):


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

Espero Esta ilustração mostra ..

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top