【发布时间】:2018-08-27 20:49:34
【问题描述】:
场景
让test 成为我们以__main__ 运行的模块。该模块包含一个名为primes 的全局变量,该变量在模块中通过以下赋值进行初始化。
primes = []
该模块还包含一个名为pi 的函数,它会改变这个全局变量:
def pi(n):
global primes
"""Some code that modifies the global 'primes' variable"""
然后我想使用内置的timeit 模块来计时所述功能。我想使用timeit.repeat函数并获取计时的最小值,作为提高测量精度的一种方式(而不是只测量一次,由于不相关的过程可能会导致速度变慢)。
print(min(timeit.repeat('test.pi(50000)',
setup="import test",
number=1, repeat=10)) * 1000)
问题在于 pi 函数的行为取决于 primes 的值:我预计,对于每次重复,setup 参数中的 import test 语句将重新运行 primes = [] test 中的语句,因此“重置”primes 以便每次重复执行的代码都是相同的。但是,取而代之的是使用上一次执行产生的primes 的值,所以我不得不将语句test.primes = [] 添加到setup 参数中:
print(min(timeit.repeat('test.pi(50000)',
setup="import test \n" + "test.primes = []",
number=1, repeat=10)) * 1000)
问题
这让我想到了一个问题:是否有直接的方法(即在一个语句中)将 all 全局变量的值“重置”为它们在模块?
在这种特定情况下,添加一条语句以手动“重置”primes 可以正常工作,但考虑有很多全局变量的情况,并且您想要“重置”所有变量。
支线问题
为什么语句import test 不重新运行初始的primes = [] 赋值?
【问题讨论】:
-
"但是考虑一个有很多全局变量的情况,你想'重置'所有变量。"那只是糟糕的程序设计。我建议您编写代码,使其不依赖于可变的全局状态,这是一种经典的反模式。
-
但是如果你坚持设计不佳,你可以使用
import importlib; importlib.reload('test') -
如果您询问在外部“重复”循环或单独的 timeit 调用之间保留的全局变量,那么您的问题是您希望
import进行干净的重新导入,而您可以通过del sys.imports['test']轻松地做到这一点,或者通过编写一个手动导入和准备test.py而不首先将其添加到sys.modules的 5 行函数来干净地做到这一点。 -
@juanpa.arrivillaga 我不认为你想要
reload。这将强制重新编译源代码,这通常只是不必要的开销。此外,它实际上并没有重置全局变量——如果有执行primes = []的顶级模块代码,则该代码将重新运行,所以谁在乎……但如果测试函数中有一些可怕的代码执行类似的操作globals().setdefault('primes', [])(考虑到这个问题,我不会立即驳回……),它不会。 -
@abarnert 谢谢。我想如果我想编写一个不添加到
sys.modules的自定义“导入函数”,我会在您链接的文档中找到所需的资源?