I want to load class
dynamically
.
I have three files, MainClass.py
, MyClassA.py
and MyClassB.py
. Why do I run different results
from MainClass.py
and MyClassA.py
?
When running from MainClass.py
, the result is:
B
Which is the result I want.
When running from MyClassA.py
, the result is :
MainClass.property is None!
The code of MainClass.py is as follows:
from MyClassA import MyClassA, main
if __name__ == '__main__':
MyClassA.property = 'B'
main()
The code of MyClassA.py is as follows:
import importlib
class MyClassA:
property = None
def main():
module_name = 'MyClass' MyClassA.property
class_name = module_name
module_object = importlib.import_module(module_name)
module_class_object = getattr(module_object, class_name)
'''
The reason why I quote MyClassA here is that because module_class_object is dynamically loaded,
PyCharm cannot automatically prompt related content when writing code,
and the upper class is subject to the first one,
so I put MyClassA in the second referenced for my convenience PyCharm writes code.
'''
class MainClass(module_class_object, MyClassA):
pass
if MainClass.property is None:
print('MainClass.property is None!')
else:
print(MainClass.property)
if __name__ == '__main__':
MyClassA.property = 'B'
main()
The code of MyClassB.py is as follows:
from MyClassA import MyClassA
class MyClassB(MyClassA):
pass
CodePudding user response:
This is because the MyClassA
object which gets imported in MyClassB.py
is different from MyClassA.py:MyClassA
when calling that script as the main script. The reason is that Python will create a new module object for the import (which is distinct from the __main__
module). You can verify that by adding print(MainClass.mro())
after the class definition which will output the following:
# python MainClass.py
[<class 'MyClassA.main.<locals>.MainClass'>,
<class 'MyClassB.MyClassB'>,
<class 'MyClassA.MyClassA'>,
<class 'object'>]
# python MyClassA.py
[<class '__main__.main.<locals>.MainClass'>,
<class 'MyClassB.MyClassB'>,
<class 'MyClassA.MyClassA'>,
<class '__main__.MyClassA'>,
<class 'object'>]
Now because you define class MainClass(module_class_object, MyClassA)
, the module_class_object
appears earlier in the MRO. I.e. when you ask for MainClass.property
it will find that attribute in <class 'MyClassA.MyClassA'>
rather than <class '__main__.MyClassA'>
which is the class you modified.
On the other hand, when running python MainClass.py
, then both modules (__main__
and MyClassB.py
) import the same module object MyClassA
since it is cached in sys.modules
. Hence all changes to objects defined in this module are shared across all other modules that use the module MyClassA
.