# exec的坑
# 概述
在 Python 中,eval() 函数用于将字符串作为 Python 表达式来求值并返回结果。可以将一个字符串解析为一个表达式,并将表达式的结果返回。该函数常用于从外部获取一些动态的表达式并计算其结果。
eval() 的函数签名如下:
exec(source, globals=None, locals=None, /)
Execute the given source in the context of globals and locals.
The source may be a string representing one or more Python statements
or a code object as returned by compile().
The globals must be a dictionary and locals can be any mapping,
defaulting to the current globals and locals.
If only globals is given, locals defaults to it.
>>> dis.dis('exec("a=1")')
1 0 LOAD_NAME 0 (exec)
2 LOAD_CONST 0 ('a=1')
4 CALL_FUNCTION 1
6 RETURN_VALUE
其中,expression 表示待求值的字符串表达式,globals 和 locals 分别表示全局命名空间和局部命名空间,如果不传入这两个参数,则默认使用当前的全局和局部命名空间。
下面是一个使用 eval() 函数的简单示例:
# 计算字符串表达式的值
expr = "2 + 3 * 4"
result = eval(expr)
print(result) # 输出:14
# 在指定命名空间下计算表达式
x = 1
y = 2
expr = "x + y"
result = eval(expr, {'x': 3, 'y': 4})
print(result) # 输出:7
# 在指定命名空间下计算包含函数调用的表达式
def add(x, y):
return x + y
expr = "add(a, b)"
result = eval(expr, {'a': 1, 'b': 2, 'add': add})
print(result) # 输出:3
需要注意的是,eval() 函数对于不安全的字符串表达式(例如来自用户输入的字符串)存在安全隐患,可能会导致代码注入攻击等问题,因此在使用时需要格外小心,避免执行恶意代码。
# eval的坑
注意eval的执行结果在局部环境中可能并不会生效,使用时需要注意。
## GLOBAL - APPLIED
g = 1
print(globals()) # {'g': 1}
exec('g = 2')
exec('g2 = 1')
print(globals()) # {'g': 2, 'g2': 1}
print(g) # 2
print(g2) # 1
globals()
print(globals()) # {'g': 2, 'g2': 1}
print(g) # 2
print(g2) # 1
print('func1 ##################################')
## Local - UNAPPLIED
def func1():
l1 = 1
print(locals()) # {'l1': 1}
exec('l1 = 2')
exec('ll1 = 1')
print(locals()) # {'l1': 1}
func1()
print('func2 ##################################')
## Local - APPLIED
def func2():
l2 = 1
loc = locals()
print(loc) # {'l2': 1}
exec('l2 = 2')
# exec('ll2 = 1')
print(loc) # {'l2': 1, 'loc': {...}, 'll2': 1}
print(locals()) # {'l2': 1, 'loc': {...}, 'll2': 1}
# print(ll2) # NameError: name 'll2' is not defined
print(locals().get('ll2')) # 1
func2()
print('func3 ##################################')
## LOCAL - UNAPPLIED
def func3():
x = 0
loc = locals()
print(loc) # {'x': 0}
exec('x += 1') # {'x': 1, 'loc': {...}}
print(loc)
locals() # {'x': 0, 'loc': {...}}
print(loc)
func3()
print('func4 ##################################')
## Local - UNAPPLIED
def func4():
l2 = 1
loc = locals()
print(loc) # {'l2': 1}
exec('l2 = 2')
print(loc) # {'l2': 2, 'loc': {...}}
print(locals()) # {'l2': 1, 'loc': {...}}
print(l2) # 1
func4()
"""
>>> dis.dis('exec("a=1")')
1 0 LOAD_NAME 0 (exec)
2 LOAD_CONST 0 ('a=1')
4 CALL_FUNCTION 1
6 RETURN_VALUE
exec(source, globals=None, locals=None, /)
Execute the given source in the context of globals and locals.
The source may be a string representing one or more Python statements
or a code object as returned by compile().
The globals must be a dictionary and locals can be any mapping,
defaulting to the current globals and locals.
If only globals is given, locals defaults to it.
"""