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?


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

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)

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

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)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.