Python Timeit和“全局名称未定义”

7 投票
2 回答
8484 浏览
提问于 2025-04-17 09:31

我在使用timing函数来优化代码时遇到了问题。例如,我在一个文件里写了一些带参数的函数,我们叫这个文件为 myfunctions.py,里面包含了:

def func1(X):
    Y = X+1
    return Y

然后我在另一个文件 test.py 中测试这个函数,在这里我调用了计时器函数来测试代码的性能(当然是更复杂的问题!),这个文件包含了:

import myfunctions
X0 = 1
t = Timer("Y0 = myfunctions.func1(X0)")
print Y0
print t.timeit()

这里的 Y0 没有被计算出来,即使我把 print Y0 这一行注释掉,还是出现了错误 global name 'myfunctions' is not defined

如果我用以下命令来指定设置:

t = Timer("Y0 = myfunctions.func1(X0)","import myfunctions")

那么就出现了另一个错误 global name 'X0' is not defined

有没有人知道怎么解决这个问题?非常感谢。

2 个回答

4

你之所以看到Y0是未定义的,是因为你在字符串里定义了它,但在执行的开始阶段,这个字符串还没有被计算出来,所以变量还没有被创建。为了让它在使用之前就被定义好,可以在脚本的开头加一句Y0 = 0

所有外部的函数和变量都必须通过Timersetup参数来传递。所以你需要像这样写"import myfunctions; X0 = 1"作为设置参数。

这样就可以正常工作了:

from timeit import Timer
import myfunctions
X0 = 1
Y0 = 0     #Have Y0 defined
t = Timer("Y0 = myfunctions.func1(X0)", "import myfunctions; X0 = %i" % (X0,))
print t.timeit()
print Y0

你可以看到我用了"X0 = %i" % (X0,)来传入外部变量X0的真实值。

还有一点你可能想知道的是,如果你的主文件里有任何函数想在timeit中使用,可以通过传递from __main__ import *作为第二个参数,让timeit识别它们。


如果你希望timeit能够修改你的变量,就不要把字符串传给它。更方便的做法是传递可调用的对象。你应该传递一个可以改变你想要的变量的可调用对象。这样你就不需要setup了。看:

from timeit import Timer
import myfunctions

def measure_me():
    global Y0    #Make measure_me able to modify Y0
    Y0 = myfunctions.func1(X0)

X0 = 1
Y0 = 0     #Have Y0 defined
t = Timer(measure_me)
print t.timeit()
print Y0

如你所见,我把print Y0放在了print t.timeit()之后,因为在执行之前,变量的值是不能被改变的!

6

你需要一个叫做 setup 的参数。试试这个:

Timer("Y0 = myfunctions.func1(X0)", setup="import myfunctions; X0 = 1")

撰写回答