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 (объект)" устранил мою проблему! спасибо
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 это стало поведением по умолчанию?
Geo

6
2.2 был, когда были представлены классы нового стиля, 3.0 - там, где они стали по умолчанию.
Cody Brocious

7
@tsunami, если хочешь достичь суперкласса, делай «Ха (сам)»
Джеймс Брэди

Я думаю, вы меня неправильно поняли. Триптих. Я помню, что использовал версию Python ниже 3.0, и я специально не говорил, что мой класс наследуется от Object, и вызов super работал. Может это поведение по умолчанию из 2.6? Просто говорю :)
Geo

Алебастр, в этом действительно нет необходимости. Уроки нового стиля имеют огромное количество преимуществ, не только супер. Нельзя продвигать старые методы.
Cody Brocious

14

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

Бывают случаи, когда вы ожидаете множественного наследования и, возможно, захотите этого, но пока вы не узнаете сложные детали MRO, лучше не трогать его и придерживаться следующих правил:

 X.a(self)

2
это правильно, потому что за 6 месяцев работы с Python / Django я использовал super как «общее правильное решение»?
philgo20

1
Ну, это не повредит вам из-за одиночного наследования само по себе (за исключением того, что оно немного медленнее), но и само по себе это ничего не даст. Вы должны разработать любые методы, которые должны наследовать умножением (в первую очередь __init__), чтобы передавать аргументы чистым и разумным способом, иначе вы получите TypeErrors или еще хуже проблемы отладки, когда кто-то попытается наследовать умножением с использованием вашего класса. Если вы действительно не разработали для поддержки MI таким образом (что довольно сложно), вероятно, лучше избежать предположения super, что этот метод является MI-безопасным.
bob с

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 для выполнения a (), поэтому я сделал X (). a (self), который кажется более полным, чем предыдущие ответы, по крайней мере, для приложений, с которыми я столкнулся. Это не кажется хорошим способом решения проблемы из-за ненужных построений и разрушений, но работает нормально.

Моим конкретным приложением был модуль Python cmd.Cmd, который по какой-то причине явно не является объектом NewStyle.

Конечный результат:

X().a(self)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.