Python super () піднімає TypeError


109

У Python 2.5 наступний код підвищує 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

Якщо я замінити class Xз class X(object), він буде працювати. Яке пояснення цьому?


3
ваша "однак я заміню клас X класом X (об'єктом)" вирішила мою проблему! thanx
AliBZ

Відповіді:


132

Причина полягає в тому, що super()працює лише на класах нового стилю , що в серії 2.x означає, що поширюється на 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
З якої версії python це стало поведінкою за замовчуванням?
Гео

6
2.2 було введено класи нового стилю, 3.0 - це дефолт.
Cody Brocious

7
@tsunami, якщо ви хочете потрапити в суперклас, зробіть "Xa (self)"
Джеймс Брейді,

Я думаю, ти мене зрозумів неправильно. Триптих. Я пам’ятаю, що використовував версію python менше 3,0, і я спеціально не говорив, що мій клас успадковує від Object, а виклик супер працював. Можливо, це поведінка за замовчуванням з 2.6? Просто кажу :)
Гео

Алебастер, в цьому насправді немає потреби. Класи в новому стилі мають величезну кількість переваг, а не просто супер. Не слід рекламувати способи старого стилю.
Cody Brocious

14

Крім того, не використовуйте super (), якщо не потрібно. Ви можете не підозрювати не про "правильну річ" загального призначення.

Бувають випадки, коли ви очікуєте багаторазового успадкування і, можливо, цього захочете, але поки ви не дізнаєтесь волохаті подробиці MRO, краще залишити його в спокої і дотримуватися:

 X.a(self)

2
це правильно, тому що за 6 місяців Python / Django я використовував супер як "загальну правильну справу"?
philgo20

1
Ну, це не зашкодить вам за одне успадкування саме по собі (за винятком того, що воно трохи повільніше), але воно також не отримає вам нічого самостійно. Вам потрібно розробити будь-які методи, які потребують множення-успадкування (особливо це стосується __init__) для передачі аргументів чистим та розумним способом, інакше ви отримаєте TypeErrors або ще гірші проблеми налагодження, коли хтось намагатиметься множити-успадковувати за допомогою вашого класу. Якщо ви дійсно не покликані підтримувати ІМ таким чином (що досить складно), можливо, краще уникнути того super, що метод є безпечним для МІ.
bobince

3

У разі, якщо жоден з вищезазначених відповідей це чітко не згадував. Ваш батьківський клас повинен успадкувати від "об'єкта", що по суті перетворило б його в новий клас стилів.

# 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

Вибачте, але в Python 3.x ваш другий приклад (неявне успадкування) насправді не працює в контексті згаданої проблеми.
софії

1

Я спробував різні методи Xa (); однак, здається, потрібен екземпляр X для виконання (), тому я зробив X (). a (self), який здається більш повним, ніж попередні відповіді, принаймні для програм, з якими я стикався. Це, здається, не є гарним способом вирішення проблеми, оскільки є непотрібні будівництво та руйнування, але це прекрасно працює.

Моєю конкретною програмою був модуль cmd.Cmd Python, який, очевидно, чомусь не є об’єктом NewStyle.

Остаточний результат:

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