super () завершается с ошибкой: TypeError «аргумент 1 должен быть типом, а не classobj», когда родительский объект не наследуется от объекта

198

Я получаю ошибку, которую не могу понять. Любая подсказка, что не так с моим примером кода?

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

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

print C().meth(1)

Образец тестового кода я получил с помощью встроенного метода 'super'.

Вот ошибка:

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

К вашему сведению, вот помощь (супер) от самого питона:

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)
 |
Эхсан Форуги
источник
возможный дубликат python super () поднимает TypeError! Зачем?
Пользователь
3
Мет ?? Это термин программирования или ... ты знаешь? Просьба уточнить.
Cplusplusplus
3
@Cplusplusplus: вероятно, стоит за Метод ;-)
ShadowFlame

Ответы:

337

Ваша проблема в том, что класс B не объявлен как класс "нового стиля". Измените это так:

class B(object):

и это будет работать.

super()и все вещи подкласса / суперкласса работают только с классами нового стиля. Я рекомендую вам всегда набирать это (object)в любом определении класса, чтобы убедиться, что это новый класс.

Классы старого стиля (также известные как «классические» классы) всегда имеют тип classobj; классы нового стиля имеют тип type. Вот почему вы получили сообщение об ошибке:

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

Попробуйте это, чтобы убедиться в этом:

class OldStyle:
    pass

class NewStyle(object):
    pass

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

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

Обратите внимание, что в Python 3.x все классы выполнены в новом стиле. Вы все еще можете использовать синтаксис из классов старого стиля, но вы получите класс нового стиля. Итак, в Python 3.x у вас не будет этой проблемы.

steveha
источник
Интересно, что я нашел именно эту проблему при запуске bottle.py ( bottlepy.org ), который выдает похожую ошибку (TypeError: должно быть типа, а не classobj), работающую на Py27, но не на Py33.
загрузка
В Python 3.x больше нет классов «старого стиля». Код, использующий объявление «старого стиля», по-прежнему объявляет класс «нового стиля», поэтому эта ошибка не может возникнуть в Python 3.x.
Steveha
1
Если класс B недоступен для редактирования, необходимо отредактировать класс A, чтобы не пытаться его использовать super(); класс A должен быть создан для работы с классом «старого стиля», и, возможно, лучший способ сделать это - сделать класс A самим классом «старого стиля». Конечно, я рекомендую просто обновить всю программу для работы в Python 3.x, чтобы все классы были в новом стиле независимо от того, что вы делаете; если этот вариант доступен, это лучший вариант.
стевеха
У меня та же проблема, но мой базовый класс объявлен как class B(object):. Я получаю эту ошибку из-за использования @mock.patch('module.B', autospec=B)непосредственно перед моим тестом. Есть мысли о том, как это исправить?
MikeyE
156

Кроме того, если вы не можете изменить класс B, вы можете исправить ошибку, используя множественное наследование.

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
источник
16
Я не мог не оставить комментарий, этот должен быть принят как «стандартный» ответ.
workplaylifecycle
9
Для будущих гуглов, застрявших на Python 2.6: это ответ, который вы, вероятно, хотите! Когда вы не можете изменить базовый класс (например, вы подклассифицируете стандартный библиотечный класс), это изменение в вашем собственном классе исправляет super ().
coredumperror
Это работало хорошо для меня, можете ли вы кто-нибудь объяснить, как это работает?
субро
@subro, это делает ваш класс классом «нового стиля» (где объект класса имеет тип type), в то же время оставляя подкласс класса «старого стиля» (класс объекта которого имеет тип classobj). super()работает с классами нового стиля, но не с классами старого стиля.
MarSoft
идеальный ответ!
Том
18

Если версия Python 3.X, это нормально.

Я думаю, что ваша версия Python 2.X, супер будет работать при добавлении этого кода

__metaclass__ = type

поэтому код

__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
источник
4

Я также столкнулся с опубликованной проблемой, когда использовал Python 2.7. Работает очень хорошо с питоном 3.4

Чтобы это работало в Python 2.7, я добавил __metaclass__ = typeатрибут в начало моей программы, и это сработало.

__metaclass__ : Это облегчает переход от классов старого стиля и классов нового стиля.

JON
источник