python3 exec in 命名空间_在Python3中的函数中创建动态命名的变量/在Python3中理解exec/eval/locals...

当您不确定某些东西为什么会以Python中的方式工作时,通常可以将您感到困惑的行为放在函数中,然后使用dis模块从Python字节码中反汇编它。在

让我们从代码的更简单版本开始:def foo():

exec("K = 89")

print(K)

如果您运行foo(),您将得到与更复杂函数相同的异常:

^{pr2}$

让我们把它拆开看看为什么:>>> import dis

>>> dis.dis(foo)

2 0 LOAD_GLOBAL 0 (exec)

3 LOAD_CONST 1 ('K = 89')

6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

9 POP_TOP

3 10 LOAD_GLOBAL 1 (print)

13 LOAD_GLOBAL 2 (K)

16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

19 POP_TOP

20 LOAD_CONST 0 (None)

23 RETURN_VALUE

您需要注意的操作是标记为“13”的操作。这是编译器处理在函数的最后一行中查找K的地方(print(K))。它使用的是LOAD_GLOBAL操作码,这失败了,因为“K”不是全局变量名,而是我们的locals()dict中的一个值(通过exec调用添加)。在

如果我们说服编译器将K看作一个局部变量(在运行exec之前给它一个值),那么它就会知道不去寻找一个不存在的全局变量呢?在def bar():

K = None

exec("K = 89")

print(K)

如果运行此函数,则不会给您错误,但不会打印出预期值:>>> bar()

None

让我们拆开看看为什么:>>> dis.dis(bar)

2 0 LOAD_CONST 0 (None)

3 STORE_FAST 0 (K)

3 6 LOAD_GLOBAL 0 (exec)

9 LOAD_CONST 1 ('K = 89')

12 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

15 POP_TOP

4 16 LOAD_GLOBAL 1 (print)

19 LOAD_FAST 0 (K)

22 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

25 POP_TOP

26 LOAD_CONST 0 (None)

29 RETURN_VALUE

注意“3”和“19”处使用的操作码。Python编译器使用STORE_FAST和LOAD_FAST将局部变量K的值放入插槽0,然后再将其取出。使用带编号的槽明显比从locals()这样的字典中插入和获取值快得多,这就是为什么Python编译器对函数中的所有局部变量访问都这么做。你不能通过修改locals()返回的字典来覆盖槽中的局部变量(就像exec那样,如果你不给它传递一个dict来用于它的命名空间)。在

实际上,让我们尝试一下我们函数的第三个版本,当我们将K定义为常规局部变量时,我们再次查看locals:def baz():

K = None

exec("K = 89")

print(locals())

这次您也不会在输出中看到89!在>>> baz()

{"K": None}Update and return a dictionary representing the current local symbol table.

局部变量K值所在的槽没有被exec语句更改,它只修改locals()dict。当您再次调用locals()时,Python用插槽中的值“更新”字典,用exec替换其中存储的值。在

这就是为什么医生接着说:Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.

您的exec调用正在修改locals()dict,并且您会发现它的更改并不总是被以后的代码看到。在

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值