简体   繁体   中英

Calling isinstance in main Python module

There is a strange behavior of isinstance if used in __main__ space.

Consider the following code

a.py:

class A(object):
    pass

if __name__ == "__main__":
    from b import B
    b = B()
    print(isinstance(b, A))

b.py

from a import A
class B(A):
    pass

main.py

from a import A
from b import B

b = B()
print(isinstance(b, A))

When I run main.py , I get True , as expected, but when I run a.py , I am getting False . It looks like the name of A is getting the prefix __main__ there.

How can I get a consistent behavior? I need this trick with import of B in a.py to run doctest on file a.py .

WSo what happens when you run a.py is that Python reads a.py and executes it. While doing so, it imports module b , which imports module a , but it does not reuse the definitions from parsing it earlier. So now you have two copies of the definitions inside a.py , known as modules __main__ and a and thus different __main__.A and aA .

In general you should avoid importing modules that you are executing as well. Rather you can create a new file for running doctests and use something like

import a
import doctest

doctest.testmod(a)

and remove the __main__ part from module a .

Chain of events:

  1. The a.py script is called.
  2. The class A statement is executed, creating A in the __main__ namespace.
  3. b is imported.
  4. In b.py a is imported.
  5. The class A statement is executed, creating A in the a namespace. This A in the a namespace has no relation to the A in the __main__ namespace other than having been generated by the same code. They are different objects.

I agree with Helmut that it is best to avoid such circular imports. However, if you wish to fix your code with minimal changes, you could do the following:

Let's rename b.py --> bmodule.py so we can distinguish b the module from b the variable (hopefully in your real code these names are already distinct):

class A(object):
    pass

if __name__ == "__main__":
    import bmodule
    b = bmodule.B()
    print(isinstance(b, bmodule.A))

prints

True

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM