Home > Net >  Why do I get different results when calling from different file locations?
Why do I get different results when calling from different file locations?

Time:10-07

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.

  • Related