Python super () aumenta TypeError

109

No Python 2.5, o código a seguir gera um TypeError:

>>> class X:
      def a(self):
        print "a"

>>> class Y(X):
      def a(self):
        super(Y,self).a()
        print "b"

>>> c = Y()
>>> c.a()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in a
TypeError: super() argument 1 must be type, not classobj

Se eu substituir o class Xpor class X(object), funcionará. Qual é a explicação para isso?

Geo
fonte
3
seu "porém eu substituo classe X com classe X (objeto)" resolveu meu problema! obrigado
AliBZ

Respostas:

132

A razão é que super()só opera em classes de novo estilo , o que na série 2.x significa estender de object:

>>> class X(object):
        def a(self):
            print 'a'

>>> class Y(X):
        def a(self):
            super(Y, self).a()
            print 'b'

>>> c = Y()
>>> c.a()
a
b
Cody Brocious
fonte
4
De qual versão do python isso se tornou o comportamento padrão?
Geo
6
2.2 foi quando as classes de novo estilo foram introduzidas, 3.0 é onde elas se tornaram o padrão.
Cody Brocious
7
@tsunami se você quiser chegar à superclasse, faça "Xa (self)"
James Brady
Eu acho que você me entendeu mal. Triptych. Lembro que estava usando uma versão python inferior a 3.0 e não disse especificamente que minha classe herda de Object e a chamada para super funcionou. Talvez seja o comportamento padrão do 2.6? Apenas dizendo :)
Geo
Alabaster, realmente não há necessidade disso. As classes de novo estilo têm um grande número de benefícios, não apenas super. Os métodos antigos não devem ser promovidos.
Cody Brocious
14

Além disso, não use super () a menos que seja necessário. Não é a "coisa certa" de propósito geral que você pode suspeitar fazer com classes de novo estilo.

Há momentos em que você está esperando herança múltipla e pode até querer, mas até que você saiba os detalhes complicados do MRO, é melhor deixá-lo como está e manter:

 X.a(self)
bobince
fonte
2
está correto porque nos meus 6 meses de Python / Django tenho usado super como a "coisa certa a fazer em geral"?
philgo20
1
Bem, isso não prejudica a herança única em si (exceto que é um pouco mais lenta), mas também não traz nada por conta própria. Você tem que projetar qualquer método que precise multiplicar-herdar (mais notavelmente __init__) para passar por argumentos de uma maneira limpa e sensata, caso contrário, você obterá TypeErrors ou problemas de depuração piores quando alguém tentar multiplicar-herdar usando sua classe. A menos que você realmente tenha projetado o suporte para MI dessa maneira (o que é bastante complicado), é provavelmente melhor evitar a implicação de superque o método é seguro para MI.
bobince,
3

No caso de nenhuma das respostas acima mencioná-lo claramente. Sua classe pai precisa herdar de "objeto", o que essencialmente a transformaria em uma nova classe de estilo.

# python 3.x:
class ClassName(object): # This is a new style class
    pass

class ClassName: # This is also a new style class ( implicit inheritance from object )
    pass

# Python 2.x:
class ClassName(object): # This is a new style class
    pass

class ClassName:         # This is a old style class
    pass
Abhi Tk
fonte
Desculpe, mas no Python 3.x seu segundo exemplo (herança implícita) não funciona realmente no contexto do problema mencionado.
dia
1

Tentei os vários métodos Xa (); no entanto, eles parecem exigir uma instância de X para executar a (), então fiz X (). a (self), que parece mais completo do que as respostas anteriores, pelo menos para os aplicativos que encontrei. Não parece ser uma boa maneira de lidar com o problema, pois há construção e destruição desnecessárias, mas funciona bem.

Meu aplicativo específico era o módulo cmd.Cmd do Python, que evidentemente não é um objeto NewStyle por algum motivo.

Resultado final:

X().a(self)
weberc2
fonte