为什么不将物体贴近环境?

问题描述 投票:0回答:1

我很惊讶,一个 map 构建的对象 eval 不记得其上下文。 为什么会这样? 下面的例子包含了一个 (被注释掉的) 变通方法 (还有其它的),但这不是我想要的。我试图理解为什么这种 Python 行为是可取的 (如果是的话)。 我意识到这与一个 前一个问题但我相信我的查询是不同的。

def test():
    x, y, z = 1, 2, 3
    names = 'x', 'y', 'z'
    for s in names:
        print(s, repr(s), eval(s))           #expected
    values = map(eval, names)
    #values = list(values)                   #why is this needed?
    print( [str(v) for v in values] )        #surprising NameError

系统信息:在Win 10下用CPython 3.8运行。

python python-3.x list-comprehension eval
1个回答
3
投票

你的代码的问题不在于 map但你使用列表理解来消耗地图迭代器。列表理解器在幕后创建了一个函数,并使用它来生成列表。然而,匿名函数有自己的命名空间,它的 命名空间,即 eval 正在尝试使用。这就失败了,因为 x, yz 只在 test 命名空间,而不是在内部函数的命名空间。

有几个方法可以解决这个问题。你可以将名字空间传递给 eval 显式,正如其他答案所建议的那样。或者你也可以用这样的代码,让列表理解使用的函数在你关心的变量上关闭。

def test():
    x, y, z = 1, 2, 3
    names = 'x', 'y', 'z'
    values = map(eval, names)
    print( [(x, y, z, str(v)) for v in values] ) # anonymous function will be a closure

但到目前为止,最好的方法可能是避免使用 eval 在第一时间。它的使用非常不稳定,如果你把你不能绝对信任的数据传给它,那就是一个巨大的安全风险(因为 eval 将会运行任意代码,只要你能把它结构成一个表达式)。) 对于像变量名这样的简单表达式,使用字典查找要好得多。

def test():
    data = {'x': 1, 'y': 2, 'z': 3}    # use a dictionary, rather than separate variables
    names = 'x', 'y', 'z'

    print([str(data[name]) for name in names])  # either do lookups directly

    values = map(data.get, names)               # or via map
    print([str(v) for v in values])

2
投票

因为 eval 没有访问周围环境的权限。它是一个函数,即 接受 动态执行的代码将被视为全局和局部的命名空间。默认情况下,这将是 globals()locals(). 问题是: locals()map 的列表理解中不包含你定义的变量。

一个解决方案是部分应用这些参数。

def test():
    x, y, z = 1, 2, 3
    names = 'x', 'y', 'z'
    for s in names:
        print(s, repr(s), eval(s))
    g, l = globals(), locals()
    values = map(lambda x: eval(x, g, l), names)
    print( [str(v) for v in values] )

And 再好 办法是 不用 eval 你几乎肯定不需要这样做。

为什么? map 物体在其环境上接近?这说不通啊 这到底是什么意思?被映射的函数被假定为具有它所需要的上下文,通常情况下,它是具有上下文的,除非你正在做一些黑客行为,比如使用 eval.

注,Python 始终 使用词法作用域,而你似乎认为它将使用动态作用域。它没有。关于这两种语言的相对优点可以说很多,但只要注意到几乎所有的现代语言都使用词法作用域就足够了。除了早期的Lisps,还有Bash,在我看来,它是一个很好的例子,说明在任何正常的语言中,你都想避免一堆事情。

© www.soinside.com 2019 - 2024. All rights reserved.