python - 为什么 Python 的 'exec' 行为异常?

标签 python python-3.x python-2.7 exec

为什么下面的代码可以正常工作,而后面的代码会中断?

我不确定如何用英语表达我的问题,所以我附上了我能想到的最小代码来突出我的问题。

(上下文:我正在尝试为 python 创建一个终端环境,但由于某种原因, namespace 似乎被搞乱了,下面的代码似乎是我问题的本质)

没有错误:

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

错误:

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

最佳答案

因为d没有使用exec提供的全局变量;它使用它在第一个 exec 中存储引用的映射。当您在新字典中设置 'b' 时,您永远不会在 that 函数的全局变量中设置 b

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

对比

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

如果 exec 没有以这种方式工作,那么这也会失败:

模组.py
b = None
def d():
    b

主.py
from mod import d
d()

一个函数会记住它最初创建的环境。


无法更改现有函数指向的字典。您可以明确地修改它的全局变量,也可以创建另一个函数对象:

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)

关于python - 为什么 Python 的 'exec' 行为异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47808590/

相关文章:

python - 带有 argparse 的目录路径类型

python - 将 Autocomplete=off 应用到 Django 密码重置确认表单

python - 迭代器耗尽,但 For 循环没有错误

python - 如果 pandas df 中缺少行,则创建行

python - 如何在不使用 Tkinter 的情况下捕获 Python 中的 Enter 键

python-2.7 - Sphinx - 引用来自不同位置的图像

python - Python 中的数学库和数组

python - 使用 BeautifulSoup Python 解析表

python - 完全模仿 tkinter 文本小部件中的标准输出以支持 Python 打印函数的结束参数

Python Windows `msvcrt.getch()` 只检测每 3 次按键?