有人可以解释一下它如何与Python解释器一起工作背后的逻辑吗?此行为是否仅线程本地?为什么第一个模块导入中的分配在第二个模块导入后仍然存在?我刚刚进行了长时间的调试会话,归结为这一点。
external_library.py
def the_best():
print "The best!"
modify_external_library.py
import external_library
def the_best_2():
print "The best 2!"
external_library.the_best = the_best_2
main.py
import modify_external_library
import external_library
external_library.the_best()
测试:
$ python main.py
The best 2!
对此没有任何线程本地。 somemodule.anattr = avalue
是非常全球性的行为! 在此分配之后,无论如何,属性都会永久更改(直到以后可能更改回来)。
没有神秘的机制在起作用! 分配给允许这种赋值的对象的任何属性(就像模块对象一样)只是以明显的方式工作 - 没有线程本地任何东西,没有什么奇怪的 - 并且属性赋值仍然存在,只要你分配了其属性的对象仍然存在,当然。
重复的import external_library
不会重新加载模块(reload
是一个完全独立的内置模块,import
不会调用它!) - 它只是检查sys.modules
,在该dict
中找到一个external_library
键,并将相应的值(之前由该赋值修改)绑定到适当的命名空间中命名external_library
(这里, 模块 main
的全局变量)。
模块是新式类的实例。修改模块(在本例中为函数)的属性时,您正在修改模块实例。当您尝试再次导入它(使用 import external_library
)时,您只会得到已经在 modify_external_library.py
中引用的相同模块对象。
编辑:当然,尝试再次导入相同的模块并不真正有效(正如Alex Martelli指出的那样)。加载后,模块不会重新初始化,除非使用 reload
显式初始化。
正如 Alex 指出的那样,您需要重新加载external_library
,如果它已经被导入,简单地导入它不会做任何事情。您可以通过将print
语句放入external_library
和modify_external_library
模块来检查这一点。
import modify_external_library
#import external_library
reload(external_library)
external_library.the_best()
输出
The best!
猴子修补之所以有效,是因为类在 python 中是可修改的,但允许它像这样传播的机制是,一旦导入并初始化了任何模块,以后的导入只需将现有实例添加到本地命名空间而无需重新运行初始化,这也节省了模块具有大量初始化以及允许猴子补丁的时间。