I am trying to import a class from one file and check if is an instance of that class in the file that it was defined in. The problem is that instead of returning True
from theisinstance()
function, it returns False
, because it was initialised in a different file.
Here is a working example.
Say you have file1.py
:
class Foo:
def __init__(self, arg1):
self.arg1 = arg1
def main(class_obj):
# Prints false and is type <class 'file1.Foo'>
print(type(class_obj))
print(isinstance(class_obj, Foo))
if __name__ == '__main__':
from file2 import get_class
main(get_class())
And file2.py
:
from file1 import Foo
def get_class():
foo = Foo("argument")
return foo
It prints False
and the type is <class 'file1.Foo'>
. What I found interesting is that if you initialize the Foo
class in file1
where is was defined, it returns True
.
# Add to main() function in file1
# Returns true and is type <class '__main__.Foo'>
foo_local = Foo("argument") # Class initiated in __main__ seems to work
print(type(foo_local))
print(isinstance(foo_local, Foo))
I found that if you initiate a class outside of the file where it is defined, it is a different "class" than if you initiate the class inside the file where it was defined.
# Different Classes?
<class 'file1.Foo'> # From other file (`file2.py`)
<class '__main__.Foo'> # From same file (`file1.py`)
So my question is:
How can I work around this so that even the classes initiated outside of the file1
can return True
on the isinstance()
function? To reword it, how can I make it so that the Foo
class is the "same" in file1.py
and file2.py
? I Python 3.6.7 if it matters.
The starkly simple answer is to never use
if __name__=="__main__"
. It’s a clever trick, to be sure, but it doesn’t do what anyone thinks it does. It’s supposed to make a file be a module and a script, but (because the processes for finding and running modules and scripts are so different) what it actually does is let the file be a module or a script, separately. The trick contains a hint as to this shortcoming:__name__
in a module is supposed to be its key insys.modules
, and if it’s “__main__” that’s not any normal module at all. (It is in fact possible toimport __main__
and get a module object whose attributes are the global variables in the script!)In your case, where
file1.py
gets used once as a script and then, via the modulefile2
, as a module, it is actually loaded twice. Each load creates an unrelated (if similar) classFoo
; it doesn’t matter where each class is used, just which one. (file1
could even import itself and would get the “module version”.) Note that the classes need not be “the same”; the very sameif
trick could be used to give them different members or base classes, or could even control whichclass Foo
statement is executed.If you want to use
python -m
, which is a perfectly reasonable desire for installation reasons, the least broken way of using it is via a__main__.py
in a package otherwise used viaimport
. It’s still possible to import it, which probably doesn’t do anything good, but no one (aside from naïve code that recursively imports every module in a package) will do so.