简体   繁体   中英

Why is Python's 'exec' behaving oddly?

Why does the following code work while the code after it breaks?

I'm not sure how to articulate my question in english, so I attached the smallest code I could come up with to highlight my problem.

(Context: I'm trying to create a terminal environment for python, but for some reason the namespaces seem to be messed up, and the below code seems to be the essence of my problem)

No errors:

d={}
exec('def a():b',d)
exec('b=None',d)
exec('a()',d)

Errors:

d={}
exec('def a():b',d)
d=d.copy()
exec('b=None',d)
d=d.copy()
exec('a()',d)

It is because the d does not use the globals provided by exec ; it uses the mapping to which it stored the reference in the first exec . While you set 'b' in the new dictionary, you never set b in the globals of that function.

>>> d={}
>>> exec('def a():b',d)
>>> exec('b=None',d)
>>> d['a'].__globals__ is d
True
>>> 'b' in d['a'].__globals__
True

vs

>>> d={}
>>> exec('def a():b',d)
>>> d = d.copy()
>>> exec('b=None',d)
>>> d['a'].__globals__ is d
False
>>> 'b' in d['a'].__globals__
False

If exec didn't work this way, then this too would fail:

mod.py

b = None
def d():
    b

main.py

from mod import d
d()

A function will remember the environment where it was first created.


It is not possible to change the dictionary that an existing function points to. You can either modify its globals explicitly, or you can make another function object altogether:

from types import FunctionType

def rebind_globals(func, new_globals):
    f = FunctionType(
        code=func.__code__,
        globals=new_globals,
        name=func.__name__,
        argdefs=func.__defaults__,
        closure=func.__closure__
    )
    f.__kwdefaults__ = func.__kwdefaults__
    return f


def foo(a, b=1, *, c=2):
    print(a, b, c, d)


# add __builtins__ so that `print` is found...    
new_globals = {'d': 3, '__builtins__': __builtins__}
new_foo = rebind_globals(foo, new_globals)
new_foo(a=0)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM