[翻译]  C Python: Running Python code within a context

[CHINESE]  C Python:在上下文中运行Python代码


The Python C API function PyEval_EvalCode let's you execute compiled Python code. I want to execute a block of Python code as if it were executing within the scope of a function, so that it has its own dictionary of local variables which don't affect the global state.

Python C API函数PyEval_EvalCode让你执行编译的Python代码。我想执行一段Python代码,就像它在函数范围内执行一样,因此它有自己的局部变量字典,不会影响全局状态。

This seems easy enough to do, since PyEval_EvalCode lets you provide a Global and Local dictionary:

这看起来很容易,因为PyEval_EvalCode允许您提供全局和本地字典:

PyObject* PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)

PyObject * PyEval_EvalCode(PyCodeObject * co,PyObject * globals,PyObject * locals)

The problem I run into has to do with how Python looks up variable names. Consider the following code, that I execute with PyEval_EvalCode:

我遇到的问题与Python如何查找变量名称有关。请考虑以下使用PyEval_EvalCode执行的代码:

myvar = 300
def func():
    return myvar

func()

This simple code actually raises an error, because Python is unable to find the variable myvar from within func. Even though myvar is in the local dictionary in the outer scope, Python doesn't copy it into the local dictionary in the inner scope. The reason for this is as follows:

这个简单的代码实际上引发了一个错误,因为Python无法从func中找到变量myvar。即使myvar位于外部作用域的本地字典中,Python也不会将其复制到内部作用域中的本地字典中。原因如下:

Whenever Python looks up a variable name, first it checks locals, then it checks globals, and finally it checks builtins. At module scope, locals and globals are the SAME dictionary object. So the statement x = 5 at module scope will place x in the the locals dictionary, which is also the globals dictionary. Now, a function defined at module scope which needs to lookup x won't find x within the function-scope locals, because Python doesn't copy module-scope locals into function-scope locals. But this normally isn't a problem, because it can find x in globals.

每当Python查找变量名时,首先检查本地变量,然后检查全局变量,最后检查内部变量。在模块范围内,locals和globals是SAME字典对象。因此,模块范围内的语句x = 5将x放在locals字典中,这也是全局字典。现在,在模块作用域中定义的需要查找x的函数将不会在函数作用域本地中找到x,因为Python不会将模块作用域本地复制到函数作用域本地。但这通常不是问题,因为它可以在全局变量中找到x。

x = 5
def foo():
   print(x) # This works because 'x' in globals() == True

It's only with nested functions, that Python seems to copy outer-scope locals into inner-scope locals. (It also seems to do so lazily, only if they are needed within the inner scope.)

它只有嵌套函数,Python似乎将外部局部区域复制到内部区域本地。 (它似乎懒得这么做,只要在内部范围内需要它们。)

def foo():
   x = 5
   def bar():
      print(x) # Now 'x' in locals() == True
   bar()


So the result of all this is that, when executing code at module scope, you HAVE to make sure that your global dictionary and local dictionary are the SAME object, otherwise module-scope functions won't be able to access module-scope variables.

因此,所有这些的结果是,在模块范围执行代码时,您必须确保您的全局字典和本地字典是SAME对象,否则模块范围函数将无法访问模块范围变量。

But in my case, I don't WANT the global dictionary and local dictionary to be the same. So I need some way to tell the Python interpreter that I am executing code at function scope. Is there some way to do this? I looked at the PyCompileFlags as well as the additional arguments to PyEval_EvalCodeEx and can't find any way to do this.

但在我的情况下,我不希望全球字典和本地字典是相同的。所以我需要一些方法来告诉Python解释器我在函数范围内执行代码。有办法做到这一点吗?我查看了PyCompileFlags以及PyEval_EvalCodeEx的其他参数,但无法找到任何方法。

1 个解决方案

#1


4  

Python doesn't actually copy outer-scope locals into inner-scope locals; the documentation for locals states:

Python实际上并没有将外部区域本地复制到内部区域本地;当地人的文件说明:

Free variables are returned by locals() when it is called in function blocks, but not in class blocks.

locals()在函数块中调用时返回自由变量,但在类块中不调用。

Here "free" variables refers to variables closed over by a nested function. It's an important distinction.

这里“自由”变量是指由嵌套函数关闭的变量。这是一个重要的区别。

The simplest fix for your situation is just to pass the same dict object as globals and locals:

对你的情况最简单的解决方法就是传递与globals和locals相同的dict对象:

code = """
myvar = 300
def func():
    return myvar

func()
"""
d = {}
eval(compile(code, "<str>", "exec"), d, d)

Otherwise, you can wrap your code in a function and extract it from the compiled object:

否则,您可以将代码包装在函数中并从编译对象中提取它:

s = 'def outer():\n    ' + '\n    '.join(code.strip().split('\n'))
exec(compile(s, '<str>', 'exec').co_consts[0], {}, {})

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2018 ITdaan.com 粤ICP备14056181号