Autoreload и package, вызывающие TypeError: super (type, obj): obj должен быть экземпляром или подтипом типа

У меня есть код python, охватывающий несколько файлов, которые я упаковал для удобства, в результате получив следующие 3 файла в каталоге my_package:

__init__.py

Содержание:

from file1 import *
from file2 import *

file1.py содержание:

class Base(object):
    pass

file2.py содержание:

from file1 import Base 
class Derived(Base):
    def __init__(self):
        return super(Derived, self).__init__()

Затем я выполняю в IPython:

>>>%autoreload 2
>>>import my_package
>>>t = my_package.Derived()

Пока все хорошо. Но затем я вношу изменения в файл2.py, скажем, добавляя атрибут dummy. Теперь, когда я выполняю:

>>>t = my_package.Derived()
>>>      2 class Derived(Base):
>>>      3     def __init__(self):
>>>----> 4         return super(Derived, self).__init__()
>>>      5 
>>>      6 dumm = 'asdf'
>>>
>>>TypeError: super(type, obj): obj must be an instance or subtype of type

Это не исчезнет, ​​пока я не перезапущу консоль IPython. Почему автозагрузка не заботится об этом правильно? Все работает, если я помещаю Base и Derived в один файл модуля, а не в пакет.

Ответ 1

Я не являюсь пользователем IPython, поэтому не могу точно сказать, что происходит, но я думаю, что это симптом использования from file2 import * в вашем файле __init__.py.

Когда вы создаете экземпляр своего класса Derived, используя package.Derived, вы не получаете самую последнюю версию этого класса, а старую версию, которая была текущей, когда пакет был сначала загружен, и from file2 import *. Когда вы модифицировали код модуля и перезагрузили IPython, это изменило package.file2.Derived, но не package.Derived.

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

Вы бы, вероятно, избежали этой проблемы, если бы вы напрямую обращались к package.file2.Derived. Это всегда приведет вас к текущей версии класса, которая не должна иметь проблем с вызовами super. Обратите внимание: если все еще есть экземпляры класса, которые были созданы до изменения модуля, у вас могут быть проблемы (но это, вероятно, не очень удивительно).