super () falha com erro: TypeError “o argumento 1 deve ser do tipo, não classobj” quando o pai não herda do objeto

196

Eu recebo algum erro que não consigo descobrir. Alguma pista do que está errado com o meu código de exemplo?

class B:
    def meth(self, arg):
        print arg

class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)

print C().meth(1)

Eu recebi o código de teste de amostra com a ajuda do método interno 'super'.

Aqui está o erro:

Traceback (most recent call last):
  File "./test.py", line 10, in ?
    print C().meth(1)
  File "./test.py", line 8, in meth
    super(C, self).meth(arg)
TypeError: super() argument 1 must be type, not classobj

Para sua informação, aqui está a ajuda (super) do próprio python:

Help on class super in module __builtin__:

class super(object)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)
 |  Typical use to call a cooperative superclass method:
 |  class C(B):
 |      def meth(self, arg):
 |          super(C, self).meth(arg)
 |
Ehsan Foroughi
fonte
possível duplicata do python super () gera TypeError! Por quê?
usuário
3
Meth ?? Isso é um termo de programação, ou ... você sabe? Por favor, esclareça.
Cplusplusplus
3
@Cplusplusplus: provavelmente significa Método ;-)
Sombria

Respostas:

333

Seu problema é que a classe B não é declarada como uma classe "novo estilo". Altere assim:

class B(object):

e vai funcionar.

super()e todo o material da subclasse / superclasse funciona apenas com classes de novo estilo. Eu recomendo que você tenha o hábito de sempre digitar isso(object) em qualquer definição de classe para garantir que seja uma classe de novo estilo.

As classes de estilo antigo (também conhecidas como classes "clássicas") são sempre do tipo classobj; classes new-style são do tipo type. É por isso que você recebeu a mensagem de erro exibida:

TypeError: super() argument 1 must be type, not classobj

Tente isso para ver por si mesmo:

class OldStyle:
    pass

class NewStyle(object):
    pass

print type(OldStyle)  # prints: <type 'classobj'>

print type(NewStyle) # prints <type 'type'>

Observe que no Python 3.x, todas as classes são de novo estilo. Você ainda pode usar a sintaxe das classes de estilo antigo, mas obtém uma classe de novo estilo. Portanto, no Python 3.x, você não terá esse problema.

steveha
fonte
interessante, encontrei esse problema exato ao executar o bottle.py ( bottlepy.org ), que gera um erro semelhante (TypeError: deve ser do tipo, não classobj) sendo executado no Py27, mas não no Py33.
bootload
No Python 3.x, não há mais classes "antigas". O código que usa a declaração "old-style" ainda declara uma classe "new-style", portanto, esse erro não pode ocorrer no Python 3.x.
Steveha
1
Se a classe B não estiver disponível para edição, você deverá editar a classe A para não tentar usar super(); a classe A deve ser criada para funcionar com uma classe "antiga" e, possivelmente, a melhor maneira de fazer isso seria fazer com que a classe A seja ela própria uma classe "antiga". É claro que eu recomendo apenas atualizar todo o seu programa para rodar no Python 3.x, para que todas as classes tenham um novo estilo, não importa o que você faça; se essa opção estiver disponível, é a melhor opção.
Steveha 9/07
Eu tenho o mesmo problema, mas minha classe base é declarada como class B(object):. Estou recebendo esse erro devido ao uso @mock.patch('module.B', autospec=B)imediatamente antes do meu caso de teste. Alguma ideia de como consertar isso?
MikeyE
154

Além disso, se você não puder alterar a classe B, poderá corrigir o erro usando herança múltipla.

class B:
    def meth(self, arg):
        print arg

class C(B, object):
    def meth(self, arg):
        super(C, self).meth(arg)

print C().meth(1)
frmdstryr
fonte
16
Não pude deixar de deixar um comentário, este deve ser aceito como resposta 'padrão'.
workplaylifecycle
9
Para futuros googlers presos no Python 2.6: esta é a resposta que você provavelmente deseja! Quando você não pode alterar a classe base (por exemplo, você está subclassificando uma classe de biblioteca padrão), essa alteração em sua própria classe corrige super ().
Coredumperror
Funcionou bem para mim. Alguém pode explicar como funciona?
Sub-
@subro, isso faz da sua classe uma classe de "novo estilo" (onde o objeto de classe é do tipo type) enquanto ainda está subclassificando uma classe de "estilo antigo" (cujo objeto de classe é do tipo classobj). super()funciona com classes de estilo novo, mas não com classes de estilo antigo.
MarSoft
resposta perfeita!
Tom
18

Se a versão python for 3.X, tudo bem.

Eu acho que sua versão python é 2.X, o super funcionaria ao adicionar esse código

__metaclass__ = type

então o código é

__metaclass__ = type
class B:
    def meth(self, arg):
        print arg
class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)
print C().meth(1)
yanghaogn
fonte
4

Também fiquei com o problema postado quando usei o python 2.7. Está funcionando muito bem com o python 3.4

Para fazê-lo funcionar no python 2.7, adicionei o __metaclass__ = type atributo na parte superior do meu programa e ele funcionou.

__metaclass__ : Facilita a transição das classes de estilo antigo e de estilo novo.

JON
fonte