Неожиданное поведение классов Python (подсистема импорта importlib x)

Этот вопрос касается сравнения типов, а не объектов python. Точнее, почему тип, определенный в модуле __main__, отличается от типа, импортированного модулем importlib.import_module(). Обратите внимание, что проблема не возникает (test2()), если все типы импортируются importlib.import_module().

Учитывая модуль с именем m.py:

class A(object):
    pass

class B(A):
    pass

def test1():
    # pass
    assert issubclass(B, A)

    # prepare test with imported module
    from importlib import import_module
    m = import_module('m')

    # pass
    assert issubclass(m.B, m.A)

    # fail
    assert issubclass(m.B, A)

    # fail
    assert m.A is A
    assert m.B is B

def test2():
    from importlib import import_module
    m0 = import_module('m')
    m1 = import_module('m')
    assert m0.A is m1.A
    assert m0.B is m1.B
    assert issubclass(m0.B, m1.A)

if __name__ == '__main__':
    import sys
    if len(sys.argv) == 2:
        if sys.argv[1] == 'test1':
            test1()
        if sys.argv[1] == 'test2':
            test2()

Почему python m.py test1 не работает, а python m.py test2 — нет? (проверено с py2.7.x и py3.4.x)


person Carlo Pires    schedule 02.07.2014    source источник
comment
__main__.A не тот же объект, что и m.A; вы импортировали файл дважды, один раз как основной скрипт, второй раз как модуль.   -  person Martijn Pieters    schedule 02.07.2014
comment
@MartijnPieters: я не думаю, что это дубликат. Это связано, может быть. Да, я дважды импортирую файл, это специально. Вопрос не в сравнении объектов, а в типах, поэтому я использую issubclass() и ключевое слово is. Также обратите внимание в test2(), что с importlib.import_module() сравнение типов проходит даже с разными модулями (или пространствами имен).   -  person Carlo Pires    schedule 02.07.2014
comment
Нет, я не говорю здесь о test2, я говорю о test1. Типы — это тоже просто объекты; вы проверяете, является ли m.B подклассом __main__.A. Это не. Это подкласс __main__.A, другой объект.   -  person Martijn Pieters    schedule 02.07.2014
comment
Другой ответ объясняет, почему существуют разные объекты. Если вы создали отдельный скрипт, и этот скрипт импортировал test1, он успешен.   -  person Martijn Pieters    schedule 02.07.2014
comment
@MartijnPieters: в ​​issubclass(m0.B, m1.A) m0.B и m1.A - разные объекты, но утверждение проходит. Почему?   -  person Carlo Pires    schedule 02.07.2014
comment
Нет, это не разные объекты. Импорт модуля кеша Python. sys.modules['m'] создается только один раз и возвращается для последующего импорта. Таким образом, m0 и m1 являются ссылками на один и тот же объект модуля.   -  person Martijn Pieters    schedule 02.07.2014
comment
Другими словами, m0 is m1 есть True, а в test1 вы предполагаете, что sys.modules['__main__'] is m верно, но это не так.   -  person Martijn Pieters    schedule 02.07.2014
comment
Теперь вижу, спасибо. Я думаю, что лучше всего сравнивать типы только в том случае, если они определены вне текущего модуля.   -  person Carlo Pires    schedule 02.07.2014
comment
Нет, лучше не импортировать файл скрипта как модуль.   -  person Martijn Pieters    schedule 02.07.2014