为何exec()在for循环中生效,在列表推导式中无法修改变量?
为什么exec()在for循环中能修改变量,列表推导式里却不行?
我有一个可独立运行的脚本,有时会通过外部传入参数覆盖脚本内定义的变量。用exec()实现了需求(本文不讨论该方法的安全性),但发现一个奇怪的现象:exec()在for循环中能成功修改变量,放到列表推导式里却无法生效。
测试代码如下:
foo = 1 bar = 2 externally_given = ['foo=10', 'bar=20'] for ext in externally_given: exec(ext) print('Exec in for loop ->', foo, bar) externally_given = ['foo=30', 'bar=40'] [exec(ext) for ext in externally_given] print('Exec in comprehension list ->', foo, bar)
输出结果:
Exec in for loop -> 10 20 Exec in comprehension list -> 10 20
注:测试基于Python 3.10版本
核心原因是Python 3的列表推导式拥有独立的局部作用域,而普通for循环是在当前的全局/函数作用域中执行的。
当你在for循环里调用exec(ext)时,exec默认会使用当前的全局命名空间(globals())和局部命名空间(locals()),所以赋值语句会直接修改外部的foo和bar变量。
但在列表推导式中,推导式本身会创建一个隐式的局部作用域。此时调用exec(ext)时,若不指定命名空间,exec会默认使用推导式内部的局部命名空间,而不是外部的全局/函数命名空间。所以赋值操作只会修改推导式内部的局部变量,外部的foo和bar完全不受影响。
如果想让列表推导式里的exec也能修改外部变量,可以显式指定globals()作为执行的命名空间:
foo = 1 bar = 2 externally_given = ['foo=30', 'bar=40'] [exec(ext, globals()) for ext in externally_given] print('Exec in comprehension list with globals ->', foo, bar)
运行这段代码,输出就会变成:
Exec in comprehension list with globals -> 30 40
内容的提问来源于stack exchange,提问作者Martí
相关产品推荐
相关产品推荐

