Reputation: 1195
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
.
Upvotes: 6
Views: 513
Reputation: 879591
Chain of events:
class A
statement is executed, creating A
in the __main__
namespace.b
is imported.a
is imported.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
Upvotes: 2
Reputation: 6778
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 a.A
.
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
.
Upvotes: 7