Почему вызов super() приводит к бесконечному циклу?

Недавно на собеседовании меня спросили:

Что не так со следующим кодом

class A(object):
      def __init__(self):
          super(self.__class__, self).__init__()

class B(A):
      pass

b = B()

Я не ожидал, что это приведет к бесконечной рекурсии. Почему это?

Я знаю об этих сложных местах, как описано здесь Как избежать бесконечной рекурсии с помощью super() ? поэтому я обратился к источнику объекта.init, чтобы увидеть, есть ли другие супервызовы, которые приводят к рекурсии (http://hg.python.org/cpython/file/2.7/Objects/typeobject.c#l2872) . Но, насколько я понимаю, их нет.

Так почему же?


person Max Lobur    schedule 06.09.2013    source источник
comment
В A.__init__ добавьте print type(self) перед вызовом super и должно стать понятно, что происходит.   -  person Steven Rumbalski    schedule 06.09.2013
comment
Истинный. Итак, полный поток: 1. init унаследован от B, но на самом деле он находится в классе A. 2. При вызове init self является B, поэтому super возвращает метод A, что является одним и тем же. Это правильно?   -  person Max Lobur    schedule 06.09.2013
comment
Вы не должны использовать super(self.__class__, self). Используйте super(A, self), использование динамически определяемого класса здесь не подходит.   -  person mata    schedule 06.09.2013
comment
хотя в py3 я слышал, что использование super намного больше того, как вы ожидаете, что этот пример будет работать   -  person Joran Beasley    schedule 06.09.2013
comment
Да, я видел это. Он не требует аргументов, поэтому вы не привязаны к конкретному указанному классу, и вам не нужно использовать для этого self.__class__ или type(self).   -  person Max Lobur    schedule 06.09.2013
comment
@JoranBeasley: Python 3 добавляет к функции замыкание __class__, когда вы используете super() без аргументов; super() будет использовать это закрытие плюс self для получения того же эффекта. Конечно, здесь __class__ — это класс, в котором была определена функция, а не type(self).   -  person Martijn Pieters    schedule 06.09.2013
comment
Вы можете вызвать его с аргументами или без аргументов. Если вы вызовете его с аргументами, это будет иметь тот же эффект, что и в py2.7.   -  person Shashank    schedule 06.09.2013
comment
Я до сих пор не понимаю, почему вызов super(self.__class__).__init__ работает. Разве он по-прежнему не передается в self в качестве аргумента __init__?   -  person Shashank    schedule 06.09.2013
comment
Вы о питоне 3? Я только что попробовал в python 2.7 и получил TypeError: super() принимает как минимум 1 аргумент (дан 0)   -  person Max Lobur    schedule 06.09.2013