关于locals()和globals()的记录
locals()陷阱
可以简单理解为locals()只读,globals()可读可写,因此操作locals()生成动态变量不可行,但是操作globals()生成动态变量可行,且globals()全局共用
def test():
globals()['a'] = 1
locals()['b'] = 2
test()
print(a)
print(b)
--------------------------------------
1
Traceback (most recent call last):
File "C:/Users/wayne/Desktop/StereoConstruction/testlocalglobal.py", line 12, in <module>
print(b)
NameError: name 'b' is not defined
exec作用域问题
def exec(cmd, globals=None, locals=None):
......
exec函数原型如上,
当不传递globals和locals时,exec会继承上文的locals和globals
当只传递globals时,exec会给globals自动添加__builtin__等内置内容并复制一份给locals
当globals和locals都传递时,exec会给两者都加上__builtin__等内置内容
具体的可以写点简单的代码验证
exec执行会改变下文的globals和locals,如下,
expr = """
y = 20
z = 30
print(locals())
print(globals())
"""
def func():
exec(expr)
x = 10
print(locals())
exec(expr)
# func()
print(globals())
print(locals())
print(y)
------------------------------
20
此处可行因为在exec中会改变globals()的值从而可以拿到新的变量
但是如果把exec放在一个函数里执行则不行,因为其改变不了globals(),如下
expr = """
y = 20
z = 30
print(locals())
print(globals())
"""
def func():
exec(expr)
x = 10
print(locals())
# exec(expr)
func()
print(globals())
print(locals())
print(y)
--------------------------------------------
Traceback (most recent call last):
File "C:/Users/wayne/Desktop/StereoConstruction/testlocalglobal.py", line 25, in <module>
print(y)
NameError: name 'y' is not defined
那如果在exec中改变globals应该就可以拿到新变量了吧,如下,
expr = """
globals()['y'] = 20
"""
def func():
exec(expr)
x = 10
func()
print(y)
---------------------------------
20
可以看到确实如预料的那样
给exec传递参数
考虑如下需求场景,需要在exec函数中生成一个变量并且在下文被使用
- 方案一
方案一就可以采用在exec中修改globals将后续要用的变量变成global变量,但是这样做的缺点也是显而易见的,增加了一个全局变量,并且由于IDE无法识别这种语法导致有红色波浪线强迫症无法接受,那么还可以怎么做呢,这个时候就可以利用exec的参数传递功能了
- 方案二
利用exec的参数传递功能,先来看一个错误解决方案
expr = """
a = 10
"""
def func():
a = None
exec(expr)
print(a)
func()
---------------------------------------
None
可以看到并没有完成想要的功能,为什么呢,继续分析
expr = """
print(1, locals())
a = 10
b = 20
print(2, locals())
"""
def func():
a = None
exec(expr)
print(3, locals())
print(a)
func()
--------------------------------
1 {'a': None}
2 {'a': 10, 'b': 20}
3 {'a': None, 'b': 20}
None
可以看到,由于locals()的只读特性,我们无法改变原有key='a’的值,但是可以新增key=‘b’,虽然由于只读性质这个b依旧不能被当作一个变量使用