为什么将变量作为全局变量或局部变量传递给 Python 的函数eval()会有所不同会有什么不同?
如文档中所述,Python 将复制__builtins__
到全局变量。但肯定还有其他一些我看不到的区别。
考虑以下示例函数。它接受一个字符串code
并返回一个函数对象。不允许使用内置函数(例如),但允许使用包中abs()
的所有函数。math
def make_fn(code):
import math
ALLOWED_LOCALS = {v:getattr(math, v)
for v in filter(lambda x: not x.startswith('_'), dir(math))
}
return eval('lambda x: %s' % code, {'__builtins__': None}, ALLOWED_LOCALS)
它按预期工作,不使用任何本地或全局对象:
fn = make_fn('x + 3')
fn(5) # outputs 8
但它不适用于以下math
功能:
fn = make_fn('cos(x)')
fn(5)
这会输出以下异常:
<string> in <lambda>(x)
NameError: global name 'cos' is not defined
但是当传递与全局相同的映射时,它可以工作:
def make_fn(code):
import math
ALLOWED = {v:getattr(math, v)
for v in filter(lambda x: not x.startswith('_'), dir(math))
}
ALLOWED['__builtins__'] = None
return eval('lambda x: %s' % code, ALLOWED, {})
与上面相同的示例:
fn = make_fn('cos(x)')
fn(5) # outputs 0.28366218546322625
这里详细发生了什么?