Python 不仅用字典评估

Python 不仅用字典评估,python,dictionary,Python,Dictionary,通常我可以这样使用eval: new_dict={'color':'green'} eval("color=='green'",new_dict) 在这种情况下,它将返回true,因此我知道new_dict中的颜色实际上是绿色的。现在我发现了一些代码,其中有人想使用eval,但使用了更通用的对象,而不是dict。 在以下代码中,基本上就是此人所做的: class myStuff(object): def __init__(self): self.color = "gre

通常我可以这样使用eval:

new_dict={'color':'green'}
eval("color=='green'",new_dict)
在这种情况下,它将返回true,因此我知道new_dict中的颜色实际上是绿色的。现在我发现了一些代码,其中有人想使用eval,但使用了更通用的对象,而不是dict。 在以下代码中,基本上就是此人所做的:

class myStuff(object):
    def __init__(self):
        self.color = "green"

class Dummy(dict):
    def __init__(self, node):
        dict.__init__(self)
        self.node = node

    def __getitem__(self, key):
        return(getattr(self.node, key))


node=myStuff()
new_dict = Dummy(node)
print eval("color=='green'",new_dict)
我现在想知道——上面代码的开发人员是如何知道eval在new\u dict for color上使用了方法
\uuu getitem\uuuu
?我找到了文档和python帮助函数,但找不到方法(或实际代码)的分步文档,因此我永远不会想到像上面的代码那样做。或者,使用上述方法不好,因为没有人真正知道eval方法是如何实现的,因此代码将来可能会出现一些奇怪的错误


编辑:这就是在程序中使用eval的原因:假设在一个列表mylist中有20个myStuff对象,您想用黄色对它们进行过滤,那么您可以简单地调用[n代表mylist中的n,如果eval(query,Dummy(n)],并使用'query=“color=='yellow'”。我不是专家,但我只是想知道这种方法是否会导致问题。

\uuuu getitem\uuuuuuuu
dict
用来通过关键字检索项目的。通过重写
\uuuu getitem\uuuuuuuu
并使其返回
self.node
的属性,您基本上可以将
node
转换为字典

一种更简单的方法是只使用
\uuu dict\uuu
属性,该属性执行相同的操作:

print eval("color=='green'", node.__dict__)

但实际上,请不要使用此选项。
eval()
很少是工作的正确工具,这是一个完美的例子,您不需要使用
eval
\uuuu getitem\uuuuuuuuu
dict
通过键检索项目的工具。通过覆盖
\uuu getitem\uuuuuuuuuuu
并使其返回
self.node
的属性,您基本上变成了
将节点
放入字典

一种更简单的方法是只使用
\uuu dict\uuu
属性,该属性执行相同的操作:

print eval("color=='green'", node.__dict__)

但实际上,请不要使用它。
eval()
很少是适合这项工作的工具,这是一个完美的例子,说明您不需要使用
eval
函数
\uu getitem\uuuuuuuuuu
可以模拟字典或列表(或者更准确地说,任何映射或序列)

序列和映射的参考文档在中,但是最好从模块开始,以及从模块开始的链接

总结一下基本思想,当您编写这样的代码时:

foo[bar]
expr = "color=='green'"
# ...
eval(expr, new_dict)
query = "color=={}'.format(color)
# ...
[n for n in mylist if eval(query, Dummy(n)]
Python将其翻译为*:

foo.__getitem__(bar)

定义
\uuu getitem\uuu
来模拟
dict
没有什么错

这样做是为了创建一个对象,将其属性视为dict项,这是一种常见的模式,它有一个名称(“attrdict”)

然而,使用
eval
几乎总是错误的。因此,做正确的事情使
eval
工作通常是正确的,因为你做的是正确的事情,而错误的是你首先使用
eval


在您的特定情况下,首先没有充分的理由使用
eval
。而不是:

eval("color=='green'",new_dict)
只要这样做:

new_dict['color']=='green'
expr = lambda x: x.color=='green'
# ...
expr(new_dict)
Python新手(尤其是那些在旧版本的PHP、Tcl或JavaScript上长大的人)经常想要使用
eval
的一个原因是为了得到一个可以轻松传递的表达式,函数是一级值,与字符串一样容易传递,当然,与字符串不同,它们是可调用的。您可以创建命名函数或lambda函数,或使用
分部
,关闭您想要的任何局部变量,等等

当然,除了打开一个巨大的安全漏洞、降低性能和阻碍调试之外,对于一个字符串,几乎没有什么是函数所不能做的

因此,与此不同的是:

foo[bar]
expr = "color=='green'"
# ...
eval(expr, new_dict)
query = "color=={}'.format(color)
# ...
[n for n in mylist if eval(query, Dummy(n)]
…就这样做:

new_dict['color']=='green'
expr = lambda x: x.color=='green'
# ...
expr(new_dict)

在您编辑的问题中:

下面是在程序中使用eval的原因:假设您在一个列表mylist中有20个myStuff对象,并且您想用黄色对它们进行过滤,那么您可以简单地调用[n代表mylist中的n,如果eval(query,Dummy(n)],并使用'query=“color=='yellow'”

那么,你大概在做这样的事情:

foo[bar]
expr = "color=='green'"
# ...
eval(expr, new_dict)
query = "color=={}'.format(color)
# ...
[n for n in mylist if eval(query, Dummy(n)]
但你也可以轻松做到这一点:

[n for n in mylist if n.color == color]
即使您需要更动态的东西,也可以动态构建函数,甚至比字符串更容易:

query = lambda n: n.color == color
[n for n in mylist if query(n)]
事实上,如果你真的想,你甚至可以让它完全功能化:

filter(compose(partial(operator.eq, color), attrgetter('color')), mylist)
但是Python最棒的一点是,您不必完全使用函数式或命令式,您可以编写介于25%或75%之间的内容,无论发生什么情况,都是最容易读写的


同时:

或者,使用上述方法不好,因为没有人真正知道eval方法是如何实现的,因此代码将来可能会出现一些奇怪的错误

不,这几乎从来都不是问题

首先,通常情况下,该文档足以准确预测它将做什么,所有Python实现都必须遵循该文档

在极少数需要了解更多信息的情况下,所有主要的实现都是开源的,因此您只需阅读代码即可。例如,您可以在线浏览CPython 3.3代码**


*这并不完全准确;真正的代码实际上是在类中而不是在对象中查找
\uuuu getitem\uuuu
(对于2.x中的旧式类和新类略有不同),并且处理C模块/Java包/适合Python实现的任何扩展类型,处理切片(在2.x和3.x中有所不同)等等,但这是最基本的想法

**
eval
代码已逐渐重构