2

This question is about types comparisons, not python objects. More precisely, why a type defined in __main__ module is different from the one imported by importlib.import_module(). Note that the problem doesn't happen (test2()) if all types are imported by importlib.import_module().

Given a module called 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()

Why python m.py test1 fails and why python m.py test2 doesn't? (tested with py2.7.x and py3.4.x)

Carlo Pires
  • 4,606
  • 7
  • 32
  • 32
  • `__main__.A` is not the same object as `m.A`; you imported the file twice, once as the main script, a second time as a module. – Martijn Pieters Jul 02 '14 at 13:20
  • @MartijnPieters: I don't think this is a duplicate. It's related, maybe. Yes, I'm importing the file twice, this is by purpose. The question is not about comparing objects, but types, that's why I'm using issubclass() and 'is' keyword. Note also in test2() that with importlib.import_module() the types comparisons passes even with different modules (or namespaces). – Carlo Pires Jul 02 '14 at 13:50
  • No, I am not talking about test2 here, I am talking about *test1*. *Types are just objects too*; you are testing if `m.B` is a subclass of `__main__.A`. It is not. It is a subclass of `__main__.A`, a different object. – Martijn Pieters Jul 02 '14 at 13:57
  • The other answer explains *why there are different objects*. If you created a *separate* script, and that script imported `test1`, it would *succeed*. – Martijn Pieters Jul 02 '14 at 13:59
  • @MartijnPieters: in `issubclass(m0.B, m1.A)` m0.B and m1.A are different objects, but assert passes. Why? – Carlo Pires Jul 02 '14 at 14:00
  • No, they are *not* different objects. Python caches module imports. `sys.modules['m']` created just once and is returned for subsequent imports. Thus `m0` and `m1` are references to the same module object. – Martijn Pieters Jul 02 '14 at 14:05
  • 1
    In other words, `m0 is m1` is `True`, while in `test1` you are assuming `sys.modules['__main__'] is m` to be true, but it is not. – Martijn Pieters Jul 02 '14 at 14:06
  • Now I see, thanks. I think the best path to go is to **compare types only if they are defined outside the current module**. – Carlo Pires Jul 02 '14 at 14:12
  • No, the best path is not to import the script file as a module. – Martijn Pieters Jul 02 '14 at 14:16

0 Answers0