重新加载函数无法擦除已删除的变量
Reload function fails to erase removed variables
我正在尝试从正在修改的 模块 访问变量,而主要的 script 运行s 通过使用重新加载。但是 reload 函数无法擦除已从 module 中删除的变量。如何强制 python 删除它们?
这是我的代码
我的module.py:
a = 1
b = 2
我的主scipt.py:
import time
from importlib import reload
import module
while True:
reload(module)
print('------- module reloaded')
try:
print('a: ', module.a)
except AttributeError:
print('a: ', 'undefined')
try:
print('b: ', module.b)
except AttributeError:
print('b: ', 'undefined')
try:
print('c: ', module.c)
except AttributeError:
print('c: ', 'undefined')
time.sleep(5)
正如预期的那样,如果我 运行 我的 脚本 和 python (3.5.1) 我得到输出:
------- module reloaded
a: 1
b: 2
c: undefined
但是当我按如下方式更改 module.py 时,出现了意外行为:
# a = 1
b = 3
c = 4
我有以下输出:
------- module reloaded
a: 1
b: 3
c: 4
这意味着 reload 正确更新了 b 的值并添加了新变量 c.但是它未能擦除已从 module 中删除的变量 a。它似乎只对在新版本 模块 中找到的变量执行更新。如何强制 reload 函数删除删除的值?
感谢您的帮助
这是设计使然。来自 docs:
When a module is reloaded, its dictionary (containing the module’s global variables) is retained. Redefinitions of names will override the old definitions, so this is generally not a problem. If the new version of a module does not define a name that was defined by the old version, the old definition remains.
通常,reload
是为了在交互式口译会话中方便;它并不是真的要在真实脚本中使用。您可能应该重新考虑您的设计。 (例如,module
不能成为常规文本文件是否有原因?)
这里的问题是 reload
是用代码实现的,粗略地说,exec
是现有缓存模块命名空间中模块代码的当前版本。这样做的原因是 reload
旨在产生全球影响; reload(module)
不只是为 you 重新加载它,它会更改每个其他模块的 module
的个人导入副本。如果它创建了一个 new 模块命名空间,其他模块仍然会缓存旧模块;虽然在 exec
ing 之前擦除旧模块的内容可能会有帮助,但它可能会破坏已经导入的包的子模块,触发竞争条件(线程可能会在 [=12] 之前和之后看到 module.a
=], 但它会在 reload
) 期间神秘消失片刻
When a module is reloaded, its dictionary (containing the module’s global variables) is retained. Redefinitions of names will override the old definitions, so this is generally not a problem. If the new version of a module does not define a name that was defined by the old version, the old definition remains.
如果您绝对必须这样做,有一些解决方法可以绕过此安全机制。最简单的是简单地从模块缓存中删除模块并重新导入它,而不是 reload
ing 它:
import sys # At top of file
del sys.modules['module']
import module
这不会更新该模块的任何其他导入器(它们将保留陈旧的缓存),但如果该模块仅在您的模块中使用,那将起作用。
另一种 可能 有效的方法(未经测试,有点疯狂)是在 [=12= 之前从模块中显式删除所有 public 名称] 与类似的东西:
# Intentionally done as list comprehension so no modification to module's globals dict
# occurs while we're iterating it
# Might make sense to use dir or iterate module.__all__ if available instead of using vars;
# depends on design
for name in [n for n in vars(module) if not n.startswith('_')]:
try:
delattr(module, name)
except Exception:
pass # Undeletable attribute for whatever reason, just ignore and let reload deal with it
reload(module) # Now exec occurs in clean namespace
这将避免过时的缓存问题,以换取精神错乱。
真的,答案是“不要使用依赖生产的设计 reload
ing”;如果模块只是数据,将其存储为 JSON 文件或类似文件并重新解析它(通常比 Python 导入机器便宜 很多 通过导入模块)。
我正在尝试从正在修改的 模块 访问变量,而主要的 script 运行s 通过使用重新加载。但是 reload 函数无法擦除已从 module 中删除的变量。如何强制 python 删除它们?
这是我的代码
我的module.py:
a = 1
b = 2
我的主scipt.py:
import time
from importlib import reload
import module
while True:
reload(module)
print('------- module reloaded')
try:
print('a: ', module.a)
except AttributeError:
print('a: ', 'undefined')
try:
print('b: ', module.b)
except AttributeError:
print('b: ', 'undefined')
try:
print('c: ', module.c)
except AttributeError:
print('c: ', 'undefined')
time.sleep(5)
正如预期的那样,如果我 运行 我的 脚本 和 python (3.5.1) 我得到输出:
------- module reloaded
a: 1
b: 2
c: undefined
但是当我按如下方式更改 module.py 时,出现了意外行为:
# a = 1
b = 3
c = 4
我有以下输出:
------- module reloaded
a: 1
b: 3
c: 4
这意味着 reload 正确更新了 b 的值并添加了新变量 c.但是它未能擦除已从 module 中删除的变量 a。它似乎只对在新版本 模块 中找到的变量执行更新。如何强制 reload 函数删除删除的值?
感谢您的帮助
这是设计使然。来自 docs:
When a module is reloaded, its dictionary (containing the module’s global variables) is retained. Redefinitions of names will override the old definitions, so this is generally not a problem. If the new version of a module does not define a name that was defined by the old version, the old definition remains.
通常,reload
是为了在交互式口译会话中方便;它并不是真的要在真实脚本中使用。您可能应该重新考虑您的设计。 (例如,module
不能成为常规文本文件是否有原因?)
这里的问题是 reload
是用代码实现的,粗略地说,exec
是现有缓存模块命名空间中模块代码的当前版本。这样做的原因是 reload
旨在产生全球影响; reload(module)
不只是为 you 重新加载它,它会更改每个其他模块的 module
的个人导入副本。如果它创建了一个 new 模块命名空间,其他模块仍然会缓存旧模块;虽然在 exec
ing 之前擦除旧模块的内容可能会有帮助,但它可能会破坏已经导入的包的子模块,触发竞争条件(线程可能会在 [=12] 之前和之后看到 module.a
=], 但它会在 reload
) 期间神秘消失片刻
When a module is reloaded, its dictionary (containing the module’s global variables) is retained. Redefinitions of names will override the old definitions, so this is generally not a problem. If the new version of a module does not define a name that was defined by the old version, the old definition remains.
如果您绝对必须这样做,有一些解决方法可以绕过此安全机制。最简单的是简单地从模块缓存中删除模块并重新导入它,而不是 reload
ing 它:
import sys # At top of file
del sys.modules['module']
import module
这不会更新该模块的任何其他导入器(它们将保留陈旧的缓存),但如果该模块仅在您的模块中使用,那将起作用。
另一种 可能 有效的方法(未经测试,有点疯狂)是在 [=12= 之前从模块中显式删除所有 public 名称] 与类似的东西:
# Intentionally done as list comprehension so no modification to module's globals dict
# occurs while we're iterating it
# Might make sense to use dir or iterate module.__all__ if available instead of using vars;
# depends on design
for name in [n for n in vars(module) if not n.startswith('_')]:
try:
delattr(module, name)
except Exception:
pass # Undeletable attribute for whatever reason, just ignore and let reload deal with it
reload(module) # Now exec occurs in clean namespace
这将避免过时的缓存问题,以换取精神错乱。
真的,答案是“不要使用依赖生产的设计 reload
ing”;如果模块只是数据,将其存储为 JSON 文件或类似文件并重新解析它(通常比 Python 导入机器便宜 很多 通过导入模块)。