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

作者: , 共 1619 字 , 共阅读 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.

类似文章:
编程 » Python
Python 在搜索模块时,依次搜索sys.path里的位置,直到找到模块为止。下面命令可以查看当前的搜索路径:
编程 » Python
今天写一段程序时遇到一个问题,查了好一会才搞清楚。代码可以简化为下面这个小代码:
编程 » Python
在 Python 中,有时候为了获取当前运行的脚本的同目录下的另外一个文件,会这么写:
IT » Python, Ubuntu
主要是update-alternatives命令的使用。
命令行参数的初步说明,请参考argparse 模块用法实例详解,写的很清晰而详细。
相似度: 0.086
编程 » pytorch, C++
目前 pytorch 已经升级到了 1.7.0 ,但在 ubuntu 20.04 下有一个非常诡异的 bug。为此,我们只能自己编译。
上次说起遇到两个 Matlab 的效率问题,还剩下 save , load 没说。不过这个问题的结论挺简单的,就是在 save 的时候尽量指定使用-v6 选项。
相似度: 0.078
IT » GIT
GIT 的一个很大的问题是没有权限划分,所有人对项目下所有东西都有(查看)权限(只能设置分支的推送权限),无法对特定文件和文件夹设置单独的权限。这个功能只能借用 SUBMODULE 来实现。
Python 提供很多语法糖,用起来非常方便。@dataclass 就是其中之一。
编程 » Python
在 Python 里,我们可以直接用 os.system 来执行系统命令(假设下面的 strip 是一个可以处理多个文件的第三者程序):
编程 » C++, 编译链接
最近升级系统,出现好多莫名其妙的问题。其中一个便是 G++编译后,发现其中一个动态链接库引用了绝对地址。正常情况下运行ldd bin/auto应该是下面的结果:
所有数据都来自于 msci barra 的 CNE5S 模型。