Python C API 函数PyEval_EvalCode
让您可以执行编译后的 Python 代码。我想执行一个 Python 代码块,就好像它在函数的范围内执行一样,这样它就有自己的局部变量字典,不会影响全局状态。
这似乎很容易做到,因为PyEval_EvalCode
允许您提供全局和本地字典:
PyObject* PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
我遇到的问题与 Python 如何查找变量名有关。考虑以下代码,我使用以下代码执行PyEval_EvalCode
:
myvar = 300
def func():
return myvar
func()
这个简单的代码实际上引发了一个错误,因为 Python 无法myvar
从func
. 即使myvar
在外部范围的本地字典中,Python 也不会将其复制到内部范围的本地字典中。原因如下:
每当 Python 查找变量名时,首先检查locals
,然后检查globals
,最后检查builtins
。在模块范围内,locals
并且globals
是相同的字典对象。所以x = 5
模块范围内的语句将放在x
字典中locals
,字典也是globals
字典。现在,在模块范围内定义的需要查找的函数x
不会x
在函数范围内找到locals
,因为 Python 不会将模块范围的本地变量复制到函数范围的本地变量中。但这通常不是问题,因为它可以x
在globals
.
x = 5
def foo():
print(x) # This works because 'x' in globals() == True
只有嵌套函数,Python 似乎将外部范围的局部变量复制到内部范围的局部变量中。(它似乎也懒惰地这样做,只有在内部范围内需要它们时。)
def foo():
x = 5
def bar():
print(x) # Now 'x' in locals() == True
bar()
所以这一切的结果是,在模块范围内执行代码时,您必须确保全局字典和本地字典是相同的对象,否则模块范围函数将无法访问模块范围变量。
但就我而言,我不希望全局字典和本地字典相同。所以我需要一些方法来告诉 Python 解释器我正在函数范围内执行代码。有没有办法做到这一点?我查看了PyCompileFlags
以及其他参数,PyEval_EvalCodeEx
但找不到任何方法来做到这一点。