Поведение Python super() ненадежно

По какой-то причине метод super() не всегда ведет себя так, как ожидалось, возвращая:

TypeError('super(type, obj): obj must be an instance or subtype of type)'

Я понимаю, что означает ошибка. Я не понимаю, почему это появляется как ошибка. Вот фрагмент кода, который ломается. Все объекты в системе являются объектами нового стиля.

Что действительно интересно, так это то, что эта ошибка не появляется всегда. Я не знаю, чем это вызвано. Метод super() в Retrieval передает класс Retrieval, а затем сам себя как объект, что, насколько мне известно, именно так предполагается для вызова super().

Есть мысли вообще?

В файле DBConnection.py:

class DBAdminConnection(object):
    def __init__(self):
        self.user = DBUserConnection().user 
        self.submissions = DBSubmissionConnection()

В файле Retrieval.py

class Retrieval(DBConnection.DBAdminConnection): 
    def __init__(self, username=None, password=None, unique_key=None):
        super(Retrieval,self).__init__()
        if username and password:
            self.username = username
            self.user.login(username,password, config.DATABASE)
            if self.user.error:
                raise UserLoginError(username)
        self.unique_key = unique_key

person Thomas Thorogood    schedule 15.03.2012    source источник


Ответы (5)


Вы перезагружаете модули как-то в процессе? Если это так, это может объяснить эту ошибку.

isinstance(self,DBAdminConnection) может стать ложным после перезагрузки модулей, по-видимому, из-за изменений в ссылках на память.

Изменить: если вы используете приложение web.py под mod_wsgi, убедитесь, что вы отключили автоперезагрузку:

app = web.application(urls, globals(), autoreload=False)
person Eduardo Ivanec    schedule 15.03.2012
comment
Это работает через webpy. Так что это определенная возможность. Тем более, что если я убью экземпляр приложения и возродлю его, проблема исчезнет. Ух ты. Теперь возникает вопрос, как, черт возьми, это исправить. - person Thomas Thorogood; 15.03.2012
comment
@TomThorogood: как у тебя дела с приложением? Вы используете mod_wsgi? - person Eduardo Ivanec; 15.03.2012
comment
Я не думаю, что делаю это. Я добавлю это сейчас! Я не использую mod_wsgi. Я использую nginx с spawn-fcgi. Попробую отключить автозагрузку. Спасибо большое! - person Thomas Thorogood; 15.03.2012
comment
Я собираюсь отметить это как решенное; все, что вы предложили, имеет смысл, и я считаю, что решение единственное (если только в webpy нет ошибки). - person Thomas Thorogood; 15.03.2012
comment
со мной произошло именно так, как вы сказали, потому что я использовал класс в IPython с %load_ext autoreload %autoreload 2 - person P.R.; 18.02.2014

Если вы используете reload() как часть вашего рабочего процесса, вам, по-видимому, также необходимо использовать super(self.__class__, self).__init__ для инициализации наследования.

Я подозреваю, что вы обнаружите, что эта ошибка совпадает с ошибкой id(self.__class__) ==id(Retrieval).

person Hal Meyers    schedule 27.08.2013
comment
super(self.__class__, self) всегда неправильно. Это станет бесконечным циклом, если вы продолжите подкласс. - person Blckknght; 07.06.2014
comment
Что, если вы больше не будете создавать подклассы, иногда это нормально? - person cce; 15.12.2014

Я не уверен, почему возникает ошибка, но в качестве помощи при отладке вы можете обернуть вызов super в блок try/except и сделать дамп данных при возникновении исключения. Что-то вроде этого:

class Retrieval(DBConnection.DBAdminConnection): 
    def __init__(self, username=None, password=None, unique_key=None):
        try:
            super(Retrieval,self).__init__()
        except TypeError, e:
            print "Failure initialising Retrieval --> self: %r"
            raise
        if username and password:
            self.username = username
            self.user.login(username,password, config.DATABASE)
            if self.user.error:
                raise UserLoginError(username)
        self.unique_key = unique_key
person Ethan Furman    schedule 15.03.2012
comment
Ты хотел сказать, что не уверен? Потому что вы на мгновение обнадежили меня. /ухмылка - person Thomas Thorogood; 15.03.2012
comment
хаха. без проблем! Спасибо за вещь. У меня есть некоторая отладка; я просто чистил код для SO. - person Thomas Thorogood; 15.03.2012

У меня была такая же проблема, когда я запускал свой код в блокноте jupyter. Я использовал перезагрузку, поэтому я перезапустил свое ядро, чтобы проверить ответ Эдуардо Иванека, чтобы попытаться выяснить, была ли проблема в этом. Затем мой код сломался. Я обнаружил, что моя проблема связана с несколькими уровнями наследования, где нижний уровень был определен над вторым нижним уровнем в модуле.

class MyClass1(object):
'''example class 1'''

class MyClass2(MyClass1):
'''example class 2'''
    def __init__(self):
    super(MyClass2, self).__init__()

class MyClass4(MyClass3):
'''example class 4 - no __init__ definition'''

class MyClass3(MyClass2):
'''example class 3 - no __init__ definition'''

Когда я переместил MyClass4 под MyClass3, это решило проблему.

Вероятно, это ошибка новичка, поэтому она, вероятно, не решит причину исходной проблемы, описанной выше, но я решил опубликовать сообщение на случай, если есть другие новички, такие как я, которые совершают ту же ошибку.

(Извините, если мой стиль неправильный, это мой первый пост на Stack Overflow. :))

person ahnastin    schedule 20.08.2016

У меня была такая же ошибка, но я заметил, что у меня есть повторяющийся класс (моя ошибка) в том же файле.py. Ошибка исчезла, когда я переименовал второй класс A в класс B

#Just some example below, not real code
class A (object):

    def fun(self):
        super(A, self).fun()

class A (object): ##This second class with same name (A) caused the error

   def some_fun(self,x,y):
person Bernard Too    schedule 03.03.2017