注意 Python 的 imp.load_source 的重复执行特性

作者: , 共 1622 字 , 共阅读 0

imp.load_source在动态载入 python 模块时非常有用,但需要注意其特性。

假设我们有一个很简单的模块./a.py

# ./a.py
print("init ./a.py globally")
G = 0

然后测试一下importimp.load_source的行为:

# ./b.py
import imp

import a
a.G = 2
print(a, id(a), a.G)
import a
a.G = 3
print(a, id(a), a.G)
import a
a.G = 4
print(a, id(a), a.G)

b = imp.load_source("a", "./a.py")
b.G = 5
print(b, id(b), b.G, a.G)

c = imp.load_source("a", "./a.py")
c.G = 6
print(c, id(c), c.G, b.G, a.G)

d = imp.load_source("b", "./a.py")
d.G = 7
print(d, id(d), d.G, c.G, b.G, a.G)

e = imp.load_source("b", "./a.py")
e.G = 8
print(e, id(e), e.G, d.G, c.G, b.G, a.G)

那么python ./b.py的结果为:

init ./a.py globally
<module 'a' from '/home/zhangzq/room/a.py'> 140534289436320 2
<module 'a' from '/home/zhangzq/room/a.py'> 140534289436320 3
<module 'a' from '/home/zhangzq/room/a.py'> 140534289436320 4
init ./a.py globally
<module 'a' from './a.py'> 140534289436320 5 5
init ./a.py globally
<module 'a' from './a.py'> 140534289436320 6 6 6
init ./a.py globally
<module 'b' from './a.py'> 140534288844496 7 6 6 6
init ./a.py globally
<module 'b' from './a.py'> 140534288844496 8 8 6 6 6

总结如下:

  • 重复import不会重复执行模块内容。
  • imp.load_source总是会执行模块内容,即使重复导入和相同名字。
  • 不同的名字会生成不同的模块,同样名字生成同样模块。不同模块不会互相影响。指向相同模块时,在修改其中一个变量的内部成员时,另外一个变量也随之而变,因此需要特别小心。

因此需要特别注意以相同名字载入模块的情况,此时模块被重新执行,但又指向同样模块,修改时会影响对方,特别有迷惑性!

一个工程实践是,在载入时缓存,如果判断已经载入过,直接取出返回。这样可以避免模块被重复执行,尤其是当执行消耗比较大的情况下。

Q. E. D.

类似文章:
相似度: 0.238
编程 » Python
Python 在搜索模块时,依次搜索sys.path里的位置,直到找到模块为止。下面命令可以查看当前的搜索路径:
相似度: 0.127
编程 » pytorch, C++
目前 pytorch 已经升级到了 1.7.0 ,但在 ubuntu 20.04 下有一个非常诡异的 bug。为此,我们只能自己编译。
IT » Python, Ubuntu
主要是update-alternatives命令的使用。
上次说起遇到两个 Matlab 的效率问题,还剩下 save , load 没说。不过这个问题的结论挺简单的,就是在 save 的时候尽量指定使用-v6 选项。
编程 » Python, numpy
numpy 的一维向量:
IT » Markdown, Pelican, Mkdocs
最近写文档和写博客都开始用 markdown ,其中博客用得是Pelican,文档用Mkdocs。它们俩都用python-markdown模块来处理 markdown 文件。而这个模块支持扩展,可以大大提升 markdown 的表现力:
编程 »
一般而言,在 Python 里:
编程 » C++, 编译链接
最近升级系统,出现好多莫名其妙的问题。其中一个便是 G++编译后,发现其中一个动态链接库引用了绝对地址。正常情况下运行ldd bin/auto应该是下面的结果:
所有数据都来自于 msci barra 的 CNE5S 模型。