[关闭]
@1007477689 2020-07-30T09:42:40.000000Z 字数 1493 阅读 454

python之import机制

Python


1. 标准 import

  Python 中所有加载到内存的模块都放在 sys.modules 。当 import 一个模块时,首先会在这个列表中查找是否已经加载了此模块,如果加载了则只是将模块的名字加入到正在调用 import 的模块的 Local 名字空间中。如果没有加载则从 sys.path 目录中按照模块名称查找模块文件,模块可以是.py.pyc.pyd,找到后将模块载入内存,并加到 sys.modules 中,并将名称导入到当前的 Local 名字空间。

  一个模块不会重复载入。多个不同的模块都可以用 import 引入同一个模块到自己的 Local 名字空间,其实背后的 PyModuleObject 对象只有一个。说一个容易忽略的问题:import 只能导入模块,不能导入模块中的对象(类、函数、变量等)。例如:模块 A(A.py)中有个函数 getName,另一个模块不能通过 import A.getName 将 getName导入到本模块,只能用 from A import getName。

2. 嵌套 import

(1)顺序嵌套

  例如:本模块导入 A 模块(import A),A 中又 import B,B 模块又可以 import 其他模块……

  这中嵌套比较容易理解,需要注意的一点就是各个模块的 Local 名字空间是独立的。

  对于上面的例子,本模块 import A 之后本模块只能访问模块 A,不能访问模块 B 及其他模块。虽然模块 B 已经加载到内存了,如果访问还要再明确的在本模块中 import B

(2)循环嵌套

  例如:
  文件 A.py

from B import D
class C:pass

  文件 B.py

from A import C
class D:pass

  为什么执行 A 的时候不能加载 D 呢?而如果将 A.py 改为:import B 就可以了。这是怎么回事呢?

RobertChen:这跟Python内部 import 的机制是有关的,具体到 from B import D,Python 内部会分成几个步骤:

  1. 在 sys.modules 中查找符号 “B”
  2. 如果符号 B 存在,则获得符号 B 对应的 module 对象。从 的 dict 中获得符号 “D” 对应的对象,如果 “D” 不存在,则抛出异常。
  3. 如果符号 B
    不存在,则创建一个新的 module 对象 ,注意,此时,module 对象的 dict 为空。执行
    B.py 中的表达式,填充 的 dict。 从 的 dict 中获得
    “D” 对应的对象,如果 “D” 不存在,则抛出异常。

所以这个例子的执行顺序如下:

1、执行 A.py 中的 from B import D 由于是执行的 python A.py,所以在 sys.modules 中并没有 存在, 首先为 B.py 创建一个 module 对象 () , 注意,这时创建的这个 module 对象是空的,里边啥也没有, 在 Python 内部创建了这个 module 对象之后,就会解析执行 B.py,其目的是填充 这个 dict

2、执行 B.py中的from A import C 在执行B.py的过程中,会碰到这一句, 首先检查sys.modules这个module缓存中是否已经存在了, 由于这时缓存还没有缓存, 所以类似的,Python内部会为A.py创建一个module对象(), 然后,同样地,执行A.py中的语句

3、再次执行A.py中的from B import D 这时,由于在第1步时,创建的对象已经缓存在了sys.modules中, 所以直接就得到了, 但是,注意,从整个过程来看,我们知道,这时还是一个空的对象,里面啥也没有, 所以从这个module中获得符号"D"的操作就会抛出异常。 如果这里只是import B,由于"B"这个符号在sys.modules中已经存在,所以是不会抛出异常的。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注