为什么使用 'eval' 是不好的做法?
我用下面这个类来方便地存储我的歌曲数据。
class Song:
"""The class to store the details of each song"""
attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
def __init__(self):
for att in self.attsToStore:
exec 'self.%s=None'%(att.lower()) in locals()
def setDetail(self, key, val):
if key in self.attsToStore:
exec 'self.%s=val'%(key.lower()) in locals()
我觉得这样比写一大堆if/else
语句要灵活多了。不过,我听说eval
不安全。真的是这样吗?有什么风险呢?我该怎么解决我这个类里的问题(动态设置self
的属性),又不冒这个风险呢?
8 个回答
是的,确实可以:
用Python来搞定:
>>> eval(input())
"__import__('os').listdir('.')"
...........
........... #dir listing
...........
下面的代码会列出在Windows电脑上运行的所有任务。
>>> eval(input())
"__import__('subprocess').Popen(['tasklist'],stdout=__import__('subprocess').PIPE).communicate()[0]"
在Linux系统上:
>>> eval(input())
"__import__('subprocess').Popen(['ps', 'aux'],stdout=__import__('subprocess').PIPE).communicate()[0]"
使用 eval
并不是一个明显的“坏”做法,但它确实有一些缺点。
它违反了“软件的基本原则”。你的源代码并不是唯一可以执行的内容。除了你的源代码,还有传给
eval
的参数,这些参数必须被清楚理解。因此,eval
只应该在最后的情况下使用。这通常是设计不周的表现。动态生成源代码的情况很少有好的理由。几乎所有的事情都可以通过委托和其他面向对象的设计方法来实现。
它会导致小段代码的即时编译速度相对较慢。这种额外的开销可以通过更好的设计模式来避免。
顺便提一下,在一些极端不理智的人手中,使用 eval
可能会带来不好的结果。不过,如果你遇到这些极端不理智的用户或管理员,最好根本就不要给他们解释型的 Python。在真正邪恶的人手中,Python 可能会变得危险;而 eval
并不会增加这种风险。
是的,使用 eval
是一种不好的做法。这里有几个原因:
- 几乎总有更好的方法可以实现同样的功能
- 非常危险且不安全
- 让调试变得困难
- 运行速度慢
在你的情况下,可以使用 setattr 来代替:
class Song:
"""The class to store the details of each song"""
attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
def __init__(self):
for att in self.attsToStore:
setattr(self, att.lower(), None)
def setDetail(self, key, val):
if key in self.attsToStore:
setattr(self, key.lower(), val)
有些情况下你确实需要使用 eval
或 exec
,但这些情况很少见。在你的情况下,使用 eval
绝对是不好的做法。我强调这是不好的做法,因为 eval
和 exec
经常在错误的地方被使用。
回复评论:
看起来有些人不同意在这个特定情况下 eval
是“非常危险且不安全”的说法。这可能在这个特定情况下是对的,但一般来说并不是。问题是比较普遍的,我列出的理由在一般情况下也是成立的。