5

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

 3 years ago
source link: https://zhiqiang.org/coding/imp-load-source.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

作者: 张志强

, 发表于 2021-01-26

, 共 1622 字 , 共阅读 80 次

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.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK