为什么在使用 timeit 或 exec 函数时不会在提供的全局命名空间中搜索函数内的变量?
Why variables inside a function don't get searched in provided global namespace when using timeit or exec function?
作为一个最小的例子,我想要 timeit fn
函数,其中有一个 x
变量。所以我将 {'x': 20, 'fn': fn}
作为我的全局命名空间传递:
from timeit import timeit
def fn():
print('This line executed.')
return x
print(timeit('fn()', globals={'x': 20, 'fn': fn}, number=1_000_000))
我以为因为x
不是本地的,所以Python检查全局命名空间来找到它。然后我返回 "This line executed."
,然后是一个 NameError,上面写着:name 'x' is not defined
。但是 Python 看到 {'x': 20, 'fn': fn}
命名空间,因为当我删除 'fn': fn
部分时,错误变为 name 'fn' is not defined
.
exec
函数也是如此(如果有帮助或有关系):
def fn():
print('This line executed.')
return x
s = """def fn():
print('This line executed.')
return x"""
exec('fn()', {'x': 10, 'fn': fn})
如何向x
介绍这些功能?将它们定义为模块级变量并将 globals()
字典传递给 global
参数是唯一的选择吗?
每个模块都有自己的全局变量,
当我们说 'fn': fn
时,我们的意思是:
- 在它自己的模块(例如
answer.py
)中使用 fn
,它有自己的全局变量。
所以如果answer.py
中没有像x
这样的全局变量,fn
就不能调用它,你会得到NameError
.
这是一个例子:
# content of answer.py
x = 10
def k1():
print(f'{globals()["x"]}')
s = """
print(globals()['x'])
"""
# uses current's module ('answer.py') global variables to run script in `s`
exec(s)
# creates new global variables to run script in `s`
exec(s, {'x': 20})
# uses current's module global variables to call `k1` in module 'answer.py' which has his own global variables
exec('k1()')
# creates new global variables to call `k1` in module 'answer.py' which has his own global variables
# when we say 'k1': k1, it means use `k1` in module 'answer.py' which has his own global variables
exec('k1()', {'k1': k1, 'x': 20})
结果:
10
20
10
10
所以如果你想告诉这些函数在你的全局变量中使用你的 x
你有一些选择,例如:
- 更改该模块的全局变量
- 不要使用模块函数并将其写入字符串并将全局变量传递给它
正如文档所说 globals()
:
Return a dictionary representing the current global symbol table. This
is always the dictionary of the current module (inside a function or
method, this is the module where it is "defined", not the module from
which it is called).
这专门解决了我的问题。所以当 Python 试图在 fn
函数中找到 x
时,(因为它不是本地或非本地的)它会去找到它的定义并查看全局命名空间 函数定义在中,而不是我们作为全局命名空间提供的全局字典。
虽然{'x': 20, 'fn': fn}
是Python可以找到标签fn
的全局字典,但是fn
函数本身并没有在那里定义,它只是叫那里。
作为一个最小的例子,我想要 timeit fn
函数,其中有一个 x
变量。所以我将 {'x': 20, 'fn': fn}
作为我的全局命名空间传递:
from timeit import timeit
def fn():
print('This line executed.')
return x
print(timeit('fn()', globals={'x': 20, 'fn': fn}, number=1_000_000))
我以为因为x
不是本地的,所以Python检查全局命名空间来找到它。然后我返回 "This line executed."
,然后是一个 NameError,上面写着:name 'x' is not defined
。但是 Python 看到 {'x': 20, 'fn': fn}
命名空间,因为当我删除 'fn': fn
部分时,错误变为 name 'fn' is not defined
.
exec
函数也是如此(如果有帮助或有关系):
def fn():
print('This line executed.')
return x
s = """def fn():
print('This line executed.')
return x"""
exec('fn()', {'x': 10, 'fn': fn})
如何向x
介绍这些功能?将它们定义为模块级变量并将 globals()
字典传递给 global
参数是唯一的选择吗?
每个模块都有自己的全局变量,
当我们说 'fn': fn
时,我们的意思是:
- 在它自己的模块(例如
answer.py
)中使用fn
,它有自己的全局变量。
所以如果answer.py
中没有像x
这样的全局变量,fn
就不能调用它,你会得到NameError
.
这是一个例子:
# content of answer.py
x = 10
def k1():
print(f'{globals()["x"]}')
s = """
print(globals()['x'])
"""
# uses current's module ('answer.py') global variables to run script in `s`
exec(s)
# creates new global variables to run script in `s`
exec(s, {'x': 20})
# uses current's module global variables to call `k1` in module 'answer.py' which has his own global variables
exec('k1()')
# creates new global variables to call `k1` in module 'answer.py' which has his own global variables
# when we say 'k1': k1, it means use `k1` in module 'answer.py' which has his own global variables
exec('k1()', {'k1': k1, 'x': 20})
结果:
10
20
10
10
所以如果你想告诉这些函数在你的全局变量中使用你的 x
你有一些选择,例如:
- 更改该模块的全局变量
- 不要使用模块函数并将其写入字符串并将全局变量传递给它
正如文档所说 globals()
:
Return a dictionary representing the current global symbol table. This is always the dictionary of the current module (inside a function or method, this is the module where it is "defined", not the module from which it is called).
这专门解决了我的问题。所以当 Python 试图在 fn
函数中找到 x
时,(因为它不是本地或非本地的)它会去找到它的定义并查看全局命名空间 函数定义在中,而不是我们作为全局命名空间提供的全局字典。
虽然{'x': 20, 'fn': fn}
是Python可以找到标签fn
的全局字典,但是fn
函数本身并没有在那里定义,它只是叫那里。