[英]Eval not only with dictionaries
通常,我可以这样使用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_dict上将__getitem__
方法用于颜色? 我找到了文档和python帮助功能,但是我找不到关于方法(或实际代码)的分步文档,因此我永远也不会想出要做什么的想法。上面的代码呢。 还是使用上述方法不好,因为没有人真正知道eval方法是如何实现的,因此代码将来可能会出现一些奇怪的错误?
编辑:这就是为什么在程序中使用eval的原因:假设您在列表mylist中有20个myStuff对象,并且想要用黄色过滤它们,那么只要eval(query, Dummy(n)]和“ query =“ color =='yellow'”。我不是专家,但我只是想知道此方法是否会导致问题。
__getitem__
是dict
用来通过其键检索项目的对象。 通过覆盖__getitem__
并使其返回self.node
的属性,您实际上可以将node
变成字典。
一种更简单的方法是只使用__dict__
属性,它执行相同的操作:
print eval("color=='green'", node.__dict__)
但实际上,不要使用它。 请。 eval()
很少是适合该工作的工具,这是不需要使用eval
的完美实例。
__getitem__
函数是一种模拟字典或列表(或更准确地说,是任何映射或序列)的方法。
序列和映射的参考文档位于Data模型中 ,但是最好的起点可能是collections.abc
模块及其中的链接。
总结基本思想,当您编写如下代码时:
foo[bar]
Python将其转换为*:
foo.__getitem__(bar)
定义__getitem__
来模拟dict
没有错。
并创建一个将其属性视为dict项的对象是一种常见的模式,它具有一个名称(“ attrdict”)。
但是,使用eval
几乎总是错误的做法。 因此,通常,做正确的事才能使eval
工作正确,因为您正在做正确的事,但错误的是您首先使用eval
。
在您的特定情况下,没有充分的理由首先使用eval
。 代替这个:
eval("color=='green'",new_dict)
只要这样做:
new_dict['color']=='green'
Python新手(尤其是那些在PHP,Tcl或JavaScript的旧版本上长大的人)经常想要使用eval
是获得一个可以轻松传递的表达式。 但是在Python(以及现代PHP和JS)中,函数是一流的值,就像字符串一样容易传递-而且,与字符串不同,它们是可调用的。 您可以创建命名或lambda函数,或使用partial
,关闭所需的任何局部变量等。
使用字符串几乎不能使用使用函数不能使用的字符串,当然,除了要打开一个巨大的安全漏洞,降低性能并阻碍调试之外,这几乎是没有的。
因此,而不是像这样:
expr = "color=='green'"
# ...
eval(expr, new_dict)
……只要这样做:
expr = lambda x: x.color=='green'
# ...
expr(new_dict)
在您编辑的问题中:
这就是为什么在程序中使用eval的原因:假设您在列表mylist中有20个myStuff对象,并且想用黄色过滤它们,那么只要eval(query,Dummy( n)]和“ query =“ color =='yellow'”。
因此,您大概正在执行以下操作:
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方法是如何实现的,因此代码将来可能会出现一些奇怪的错误?
不,那几乎从来不是问题。
首先, eval
的文档通常足以准确预测其功能,并且所有Python实现都必须遵循该文档。
在您确实需要了解更多信息的极少数情况下,所有主要实现都是开源的,因此您只需阅读代码即可。 例如,您可以在此处在线浏览CPython 3.3代码。**
*这并不完全准确; 实际的代码实际上是在类而不是对象中查找__getitem__
(2.x中的旧类与新类稍有不同),并处理C模块/ Java包/适用于您的Python实现的扩展类型,切片(在2.x与3.x中不同)等。但这是基本思想。
** eval
代码多年来已经逐步重构,因此,此时,您可以使用ast
模块和好友在几行纯Python中重新实现eval
,或者使用PyEval*
函数在几行C中重新实现eval
,因此,在不知道您关心的实现和版本的情况下,很难将您指向确切的代码行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.