Cha*_*l72 14 c python cpython python-c-api python-3.x
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()
Run Code Online (Sandbox Code Playgroud)
这个简单的代码实际上会引发错误,因为Python无法myvar从内部找到变量func.即使myvar在外部作用域中的本地字典中,Python也不会将其复制到内部作用域中的本地字典中.原因如下:
每当Python查找变量名时,首先检查locals,然后检查globals,最后检查builtins.在模块范围,locals并且globals是SAME字典对象.因此,声明x = 5在模块范围内将放置x在该locals字典,这也是globals字典.现在,在函数范围内x找不到需要查找的模块作用域定义x的函数locals,因为Python不会将模块作用域本地复制到函数作用域本地.但是,这通常是没有问题的,因为它可以找到x在globals.
x = 5
def foo():
print(x) # This works because 'x' in globals() == True
Run Code Online (Sandbox Code Playgroud)
它只有嵌套函数,Python似乎将外部局部区域复制到内部区域本地.(它似乎懒得这么做,只要在内部范围内需要它们.)
def foo():
x = 5
def bar():
print(x) # Now 'x' in locals() == True
bar()
Run Code Online (Sandbox Code Playgroud)
因此,所有这些的结果是,在模块范围执行代码时,您必须确保您的全局字典和本地字典是SAME对象,否则模块范围函数将无法访问模块范围变量.
但就我而言,我并不希望全球词典和本地词典是一样的.所以我需要一些方法来告诉Python解释器我在函数范围内执行代码.有办法做到这一点吗?我查看了PyCompileFlags以及其他参数,PyEval_EvalCodeEx并且找不到任何方法来执行此操作.
Python 实际上并没有将外部作用域本地变量复制到内部作用域本地变量中;国家的文件locals:
在功能块中调用 locals() 时会返回自由变量,而不是在类块中。
这里的“自由”变量是指被嵌套函数关闭的变量。这是一个重要的区别。
针对您的情况最简单的解决方法是传递与globalsand相同的dict 对象locals:
code = """
myvar = 300
def func():
return myvar
func()
"""
d = {}
eval(compile(code, "<str>", "exec"), d, d)
Run Code Online (Sandbox Code Playgroud)
否则,您可以将代码包装在一个函数中并从编译对象中提取它:
s = 'def outer():\n ' + '\n '.join(code.strip().split('\n'))
exec(compile(s, '<str>', 'exec').co_consts[0], {}, {})
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1647 次 |
| 最近记录: |