Python eval(compile(…), sandbox), globals go in sandbox unless in def, why?

前端 未结 3 1657
抹茶落季
抹茶落季 2020-12-18 09:18

Consider the following:

def test(s):
    globals()[\'a\'] = s

sandbox = {\'test\': test}
py_str = \'test(\"Setting A\")\\nglobals()[\"b\"] = \"Setting B\"\'         


        
3条回答
  •  执念已碎
    2020-12-18 10:17

    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.

    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).

    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
    

提交回复
热议问题