import模块#
import xxx#
定义test.py
1
import _locale
用dis模块编译一下
1
2
3
4
5
6
7C:\Users\liuw\Desktop> python.exe -m dis .\test.py
  1           0 LOAD_CONST               0 (0)
              2 LOAD_CONST               1 (None)
              4 IMPORT_NAME              0 (_locale)
              6 STORE_NAME               0 (_locale)
              8 LOAD_CONST               1 (None)
             10 RETURN_VALUE
想象一下,当前 有两个或多个线程正在导入相同的random模块,CPython如何处理这种情况?
- 操作码IMPORT_NAME将检查导入的名称是否在sys.module中,如果是,则返回 sys.module中的内容
- 尝试获取锁 **_imp**
- 使用模块名称获取_module_locks中的锁对象,如有必要,在position 1中创建
- 尝试在第3步(position 2)中获取锁定对象
- 释放锁 **_imp**(position 3)
- 检查要导入的名称是否在sys.module中,如果是,则释放_module_locks中的锁对象并返回sys.module中的内容(position 4)
- 对于 sys.meta_path中的 finder,如果finder可以加载模块名称,请释放_module_locks中的锁对象并返回已加载的内容
- raise an error 在position 1,只有拥有_imp的线程才能修改_module_locks,当前线程将检查要导入的模块名称是否在_module_locks中,如果不是,则在_module_locks中插入新的锁定对象
 
在position 4,当前线程再次检查 sys.modules中的缓存
在position 5,它将在每个 finder调用之前获取 **_imp**锁。在函数调用之后查找并释放它 
import xxx as x#
定义test.py| 1 | import demo as d | 
| 1 | C:\Users\liuw\Desktop> python.exe -m dis .\test.py | 
 
可以看出,这里仅仅是 将模块的名字变为 d
了.因此,这个 import 语句变体其实等价于:
1
2
3import demo
d = demo
del demo
from import#
定义test.py
1
from demo import value
1
2
3
4
5
6
7
8
9C:\Users\liuw\Desktop> python.exe -m dis .\test.py
  1           0 LOAD_CONST               0 (0)
              2 LOAD_CONST               1 (('value',))
              4 IMPORT_NAME              0 (demo)
              6 IMPORT_FROM              1 (value)   # 从栈顶模块中取出指定名字,并保存于栈顶
              8 STORE_NAME               1 (value)
             10 POP_TOP
             12 LOAD_CONST               2 (None)
             14 RETURN_VALUE
 
注意到,value 以 元组 的形式保存于栈顶,IMPORT_NAME 指令如果发现 value 为 demo 模块的子模块,将同时加载 value 子模块。此外,IMPORT_FROM 与 STORE_NAME 这两个指令相互配合,从模块中取出给定名字并保存。
仅仅加载了模块下的一部分
from import as#
| 1 | //from demo import func as f |