Python eval(compile(...),sandbox),除非在def中,否则全局变量会进入sandbox,为什么? [英] Python eval(compile(...), sandbox), globals go in sandbox unless in def, why?
问题描述
请考虑以下内容:
def test(s):
globals()['a'] = s
sandbox = {'test': test}
py_str = 'test("Setting A")\nglobals()["b"] = "Setting B"'
eval(compile(py_str, '<string>', 'exec'), sandbox)
'a' in sandbox # returns False, !What I dont want!
'b' in sandbox # returns True, What I want
'a' in globals() # returns True, !What I dont want!
'b' in globals() # returns False, What I want
我是甚至不知道怎么问,但是我希望函数的全局作用域成为我打算在不需要评估过程中编译函数的情况下运行它的环境。
I'm not even sure how to ask, but I want the global scope for a function to be the environment I intend to run it in without having to compile the function during the eval. Is this possible?
感谢任何输入
解决方案
def test(s):
globals()['a'] = s
sandbox = {}
# create a new version of test() that uses the sandbox for its globals
newtest = type(test)(test.func_code, sandbox, test.func_name, test.func_defaults,
test.func_closure)
# add the sandboxed version of test() to the sandbox
sandbox["test"] = newtest
py_str = 'test("Setting A")\nglobals()["b"] = "Setting B"'
eval(compile(py_str, '<string>', 'exec'), sandbox)
'a' in sandbox # returns True
'b' in sandbox # returns True
'a' in globals() # returns False
'b' in globals() # returns False
推荐答案
Python,它看到的全局变量始终是其定义所在模块的全局变量。(如果不正确,则函数为可能不起作用-实际上可能需要一些全局值,并且您不一定知道那些是全局值。)使用 exec $ c指定全局字典$ c>或
eval()
仅影响全局变量,即 exec
'或 eval()
会看到。
When you call a function in Python, the global variables it sees are always the globals of the module it was defined in. (If this wasn't true, the function might not work -- it might actually need some global values, and you don't necessarily know which those are.) Specifying a dictionary of globals with exec
or eval()
only affects the globals that the code being exec
'd or eval()
'd sees.
如果您希望某个函数看到其他全局变量,则确实必须在传递给 exec
或 eval()
。当您这样做时,函数的模块就是从其编译的字符串,带有其自己的全局变量(即,您提供的全局变量)。
If you want a function to see other globals, then, you do indeed have to include the function definition in the string you pass to exec
or eval()
. When you do, the function's "module" is the string it was compiled from, with its own globals (i.e., those you supplied).
使用与您要调用的代码对象相同的代码对象创建一个新函数,但是使用一个不同的 func_globals
属性来指向您的globals字典,但这是相当先进的黑客技术,可能并非如此值得。仍然,这是您的操作方式:
You could get around this by creating a new function with the same code object as the one you're calling but a different func_globals
attribute that points to your globals dict, but this is fairly advanced hackery and probably not worth it. Still, here's how you'd do it:
# create a sandbox globals dict
sandbox = {}
# create a new version of test() that uses the sandbox for its globals
newtest = type(test)(test.func_code, sandbox, test.func_name, test.func_defaults,
test.func_closure)
# add the sandboxed version of test() to the sandbox
sandbox["test"] = newtest
这篇关于Python eval(compile(...),sandbox),除非在def中,否则全局变量会进入sandbox,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!