我发现重新加载模块时下面的代码片段
test
出乎意料地已经在
globals()
/
locals()
中定义了所有变量。
为什么会发生这种情况?
我注意到了这个
"xxx" in locals()
模式| ||Blender Python 脚本中有很多
,因为人们通常使用它来检查模块之前是否已重新加载(通常在开发过程中会重新加载这些脚本)。由于每个人都在使用它,我想它应该在大多数情况下都可以工作。
但是使用此警告来确定模块之前是否已经加载真的安全吗(有什么想法无法工作的情况吗?)?我的意思不仅仅是开发和测试的东西,因为它看起来更像是可能在生产中中断的实现细节。
test.py:
# prints False, False, False
import test
import importlib
# prints True, True, True
importlib.reload(test)
test.py:
print("a" in globals(), "b" in globals(), "c" in globals())
# NameError: name 'a' is not defined
# print(a)
a = 25
b = 35
c = 45
当模块第一次被导入时,它会被执行。 这意味着将定义
a
、
b
和
c
,并且对它们的
print
语句将评估为
True
。这就是为什么在重新加载模块后在
globals()
中看到它们的原因。
但是,
'xxx' in locals()
不是检测模块重新加载的可靠方法。以下是它可能失败的一些原因:
-
第一次导入时该变量可能存在:
如的示例所示,如果在检查之前定义了变量,则即使模块尚未重新加载,该检查也会返回
True
。 -
该变量可能是在其他地方定义的:
globals()
和locals()
受调用它们的作用域的影响。如果另一个模块或函数在同一个名称空间中定义了xxx
,则检查可能会返回True
,即使相关模块尚未重新加载。 -
该变量可能已被明确删除:
如果一个模块确实重新加载并且出于某种原因删除了一个以前定义的变量,则该检查将返回
False
,即使该模块已重新加载。
那么,检测模块重新加载的可靠方法是什么?
Python 的
importlib
模块提供了一个可靠的方法来做到这一点:可以检查模块的
__spec__.loaded
属性。在重新加载模块后,此属性将更新为新的加载时间。
这是一个示例:
import importlib
# 第一次导入模块
import my_module
original_load_time = my_module.__spec__.loaded
# 做一些事情...
# 重新加载模块
importlib.reload(my_module)
# 检查模块是否已重新加载
if my_module.__spec__.loaded != original_load_time:
print("模块已重新加载!")
这种方法比检查
locals()
或
globals()
更可靠,因为它直接依赖于 Python 的导入机制。