pythonpython-import

Confirming what happens when importing a package?


I was surprised to find out that both the two call in main.py works:

import package_top
package_top.module.hello() # I thought this won't work ...
package_top.hello() # I thought this is the only way

package_top

package_top/
├── __init__.py
└── module.py

__init__.py

from .module import hello

module.py

def hello():
    print("module_hello")

From my understanding, when I call import package_top in main.py, it will run __init__.py which adds hello to namespace package_top, and then package_top is added to namespace main, so I can access hello with package_top.hello(). What I don't understand is why the second call also works?

I expect the prgram to throw out an error at the second line.


Solution

  • The Python import machinery modifies the package_top module object and adds the module attribute as part of importing the child module. See the Python import docs on submodules:

    When a submodule is loaded using any mechanism (e.g. importlib APIs, the import or import-from statements, or built-in __import__()) a binding is placed in the parent module’s namespace to the submodule object.

    Other import statements such as from other_package import x, y only add the x and y names to the importing module object. In your case, from .module import hello, is both importing the function hello, and also importing the submodule module of package_top, so your import statement creates both package_top.hello and package_top.module, which in turn gives you access to package_top.module.hello.

    You can confirm this by printing the module scope after importing:

    from .module import hello
    
    print(dir())
    

    prints:

    ['__builtins__', (more default __stuff__ ...), 'hello', 'module']
    

    Therefor package_top.module.hello() works without problems. Remove the from .module import hello statement and you will see the submodule is not imported, and the package_top.module.hello() statement will fail.