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.