super () не вдається з помилкою: TypeError "аргумент 1 повинен бути тип, а не classobj", коли батьків не успадковує об'єкт


196

Я отримую помилку, яку я не можу зрозуміти. Будь-яка підказка, що не так з моїм зразком коду?

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

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

print C().meth(1)

Я отримав зразок тестового коду за допомогою вбудованого методу "супер".

Ось помилка:

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

FYI, ось допомога (супер) від самого пітона:

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


3
Мет ?? Це термін програмування, чи ... ви знаєте? Поясніть будь ласка.
Cplusplusplus

3
@Cplusplusplus: напевно, означає метод ;-)
ShadowFlame

Відповіді:


334

Ваша проблема полягає в тому, що клас 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 у вас не буде цієї проблеми.


Що цікаво, я виявив, що саме ця проблема працює під керуванням bottle.py ( bottlepy.org ), яка видає аналогічну помилку (TypeError: повинен бути тип, а не classobj), що працює на Py27, але не на Py33.
завантаження

У Python 3.x більше немає класів "старого стилю". Код із використанням декларації "старого стилю" все ще оголошує клас "нового стилю", тому ця помилка не може виникнути в Python 3.x.
steveha

1
Якщо клас B недоступний для редагування, ви повинні редагувати клас A, щоб не намагатися його використовувати super(); клас A повинен бути створений для роботи з класом «старого стилю», і, можливо, найкращим способом зробити це було б, щоб клас А був сам клас «старого стилю». Звичайно, я рекомендую просто оновити всю свою програму до запуску в Python 3.x, так що всі класи будуть новим стилем, незалежно від того, що ви робите; якщо такий варіант доступний, це найкращий варіант.
steveha

У мене те саме питання, але мій базовий клас оголошено як class B(object):. Я отримую цю помилку через використання @mock.patch('module.B', autospec=B)перед моїм тестовим випадком. Будь-які думки, як це виправити?
MikeyE

154

Крім того, якщо ви не можете змінити клас 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)

16
Я не міг не залишити коментар, цей варіант слід сприймати як "стандартну" відповідь.
workplaylifecycle

9
Для майбутніх googlers застрягли на Python 2.6: це відповідь, який ви, мабуть, хочете! Якщо ви не можете змінити базовий клас (наприклад, ви підкласируєте стандартний клас бібліотеки), ця зміна виправляє ваш власний клас super ().
coredumperror

Мені це добре подіяло. Чи можете ви хтось пояснити, як це працює?
subro

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

4

Я також зіткнувся з опублікованою проблемою, коли використовував python 2.7. Він працює дуже добре з python 3.4

Щоб він працював у python 2.7, я додав __metaclass__ = typeатрибут у верхній частині своєї програми, і він працював.

__metaclass__ : Це полегшує перехід від класів старого та нового класів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.