SoFunction
Updated on 2024-10-28

python's import mechanism in detail

This article details Python's import mechanism, which is useful for understanding how Python works!

1. standard import:

All modules loaded into memory in Python are placed in . When importing a module, you first look in this list to see if the module is already loaded, and if it is, you just add the module's name to the Local namespace of the module you're calling import on. If it's not loaded, it looks up the module file in the directory by its name, which can be py, pyc, pyd, and when it's found, it loads the module into memory, adds it to the directory, and imports the name into the current Local namespace.

A module is not loaded repeatedly. Multiple different modules can import the same module into their own Local namespace using import, but there is really only one PyModuleObject object behind it. Here's an overlooked point: import can only import modules, not objects (classes, functions, variables, etc.). For example, if module A() has a function getName, another module can't import getName into this module by import, you can only use from A import getName.

2. Nested import:

1) Sequential Nesting

For example: this module imports module A (import A), which in turn imports B, which in turn can import other modules ......
This nesting is easy to understand, but it is important to note that the Local namespace of each module is independent. For the above example, after importing A into this module, this module can only access module A, not module B or any other module. Even though module B is already loaded into memory, if you want to access it, you have to explicitly import B in this module.

2) Loop nesting

Example:

Documentation []

from B import D
class C:pass

Documentation [ ]

from A import C
class D:pass

Why can't D be loaded when A is executed?
If you change it to: import B it will work.
What's going on here?

RobertChen: This has to do with Python's internal import mechanism, specifically from B import D, which is broken down into several steps inside Python:
(1) Look for the symbol "B" in the
(2) If symbol B exists, get the module object corresponding to symbol B.
Get the object corresponding to the symbol "D" from the __dict__ of <modult B> and throw an exception if "D" does not exist.
(3) If symbol B does not exist, create a new module object <module B>, note that, at this time, the __dict__ of the module object is empty.
Execute the expression in the __dict__ that populates <module B>.
Get the object corresponding to "D" from __dict__ of <module B> and throw an exception if "D" does not exist.

So the order of execution for this example is as follows:

1, the implementation of from B import D due to the implementation of python, so there is no <module B> existence, first for the creation of a module object (<module B>), note that the creation of this module object is empty, there is nothing inside, in Python internal creation of this module object will be parsed and executed, the purpose is to fill <module B> this __dict__. After Python creates the module object, it parses it and executes it to fill the <module B> __dict__.
2, the implementation of the from A import C in the process of execution, will encounter this sentence, first check whether the module cache already exists <module A>, as this time the cache has not been cached <module A>, so similar to the Python internal will be for the creation of a module object (< module A>), and then, similarly, execute the statement in
3, once again in the implementation of from B import D At this point, as in step 1, the creation of & lt; module B & gt; object has been cached in the, so directly on the & lt; module B & gt;, but, note, from the whole process, we know that this time & lt; module B & gt; is still a null object, there is nothing, so the operation from the module to get the symbol "D" will throw an exception. There's nothing in it, so the operation to get the symbol "D" from this module will throw an exception. If you just import B, the symbol "B" already exists in the module, so no exception is thrown.

ZQ:Illustration below:

3. Package import

As long as there is a __init__.py file in a folder, that folder is considered a package. The process of importing a package is basically the same as for a module, except that when you import a package, you execute the __init__.py file in the package directory instead of the statements in the module. In addition, if you are simply importing a package, and there is no other initialization operation explicitly stated in the package's __init__.py, then the modules under the package will not be imported automatically.
Example:
There is the following package structure:
  PA
  |---- __init__.py
  |----
  |---- PB1
        |---- __init__.py
        |---- pb1_m.py
  |---- PB2
        |---- __init__.py
        |---- pb2_m.py
There is the following program:

import sys
import               #1
import PA.PB1                #2
import PA.PB1.pb1_m as m1    #3
import PA.PB2.pb2_m          #4
()           #5
()                #6
.pb2_m.getName()       #7

1) After executing #1, there will be two modules at the same time, you can call any class or function under PA.PB1(2), but you cannot call any module under PA. PB1(2), you can't call any module under PA. PB1(2). Currently, there is a PA name in Local.

2) After executing #2, only PA.PB1 is loaded into memory, there will be three modules, PA, PA.PB1, but no module under PA.PB1 is loaded into memory automatically. At this time, if you execute PA.PB1.pb1_m.getName() directly, it will cause an error, because there is no pb1_m in PA.PB1. There is no pb1_m in PA.PB1. There is still only the PA name in Local, not PA.PB1.

3) After executing #3, pb1_m under PA.PB1 will be loaded into memory, and there will be four modules, PA, PA.PB1, PA.PB1.pb1_m, at this time, we can execute PA.PB1.pb1_m.getName(). Due to the use of as, in addition to the name of PA, m1 is added as an alias of PA.PB1.pb1_m in the current Local.

4) After executing #4, PA.PB2, PA.PB2.pb2_m will be loaded into the memory, and there will be six modules, PA, PA.PB1, PA.PB1.pb1_m, PA.PB2, PA.PB2.pb2_m. Currently, there are still only PA and m1 in Local.
The following #5, #6, and #7 all work correctly.

Note to self:If PA.PB2.pb2_m wants to import PA.PB1.pb1_m, it will work. It is better to use a clear import path for . /... Relative import paths are not recommended.