为了账号安全,请及时绑定邮箱和手机立即绑定

为什么使用'eval'是一种不好的做法?

为什么使用'eval'是一种不好的做法?

湖上湖 2019-05-22 15:43:42
为什么使用'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似乎被认为是一种不良做法并且使用起来不安全。如果是这样,任何人都可以向我解释为什么并告诉我一个更好的方法来定义上面的类?
查看完整描述

5 回答

?
千万里不及你

TA贡献1784条经验 获得超9个赞

是的,使用eval是一种不好的做法。仅举几个原因:

  1. 几乎总有一种更好的方法

  2. 非常危险和不安全

  3. 使调试变得困难

在您的情况下,您可以使用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经常在错误的地方使用。

编辑2:

看起来有些人不同意eval在OP情况下“非常危险且不安全”。对于这个特定情况可能也是如此,但一般情况下并非如此。问题是一般性的,我列出的原因也适用于一般情况。

编辑3: 重新排序第1点和第4点


查看完整回答
反对 回复 2019-05-22
?
繁星点点滴滴

TA贡献1803条经验 获得超3个赞

使用eval很弱,不是一个明显不好的做法。

  1. 它违反了“软件基本原理”。您的来源不是可执行文件的总和。除了你的来源之外,还有eval必须清楚理解的论据。因此,它是最后的工具。

  2. 这通常是轻率设计的标志。动态源代码很少有充分的理由,即时构建。使用委托和其他OO设计技术几乎可以做任何事情。

  3. 它导致相对较慢的动态编译小块代码。通过使用更好的设计模式可以避免开销。

作为一个脚注,在疯狂的反社会手中,它可能不会很好。然而,当面对精神错乱的反社会用户或管理员时,最好不要首先给他们解释Python。在真正邪恶的手中,Python可以承担责任; eval根本不会增加风险。


查看完整回答
反对 回复 2019-05-22
?
RISEBY

TA贡献1856条经验 获得超5个赞

是的:


使用Python的Hack:


>>> 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]"


查看完整回答
反对 回复 2019-05-22
?
慕哥6287543

TA贡献1831条经验 获得超10个赞

值得注意的是,对于所讨论的具体问题,有几种替代方法可供使用eval

如上所述,最简单的是使用setattr

def __init__(self):
    for name in attsToStore:
        setattr(self, name, None)

一种不太明显的方法是__dict__直接更新对象的对象。如果你想要做的就是将属性初始化为None,那么这比上面的要简单得多。但考虑一下:

def __init__(self, **kwargs):
    for name in self.attsToStore:
       self.__dict__[name] = kwargs.get(name, None)

这允许您将关键字参数传递给构造函数,例如:

s = Song(name='History', artist='The Verve')

它还允许您locals()更明确地使用,例如:

s = Song(**locals())

...并且,如果您真的想要分配None名称在locals()以下位置的属性:

s = Song(**dict([(k, None) for k in locals().keys()]))

为对象提供属性列表的默认值的另一种方法是定义类的__getattr__方法:

def __getattr__(self, name):
    if name in self.attsToStore:
        return None
    raise NameError, name

当以正常方式找不到命名属性时,将调用此方法。这种方法比简单地在构造函数中设置属性或更新__dict__它更简单,但它具有不实际创建属性的优点,除非它存在,这可以大大减少类的内存使用。

所有这一切:一般来说,有很多原因可以避免eval- 执行你无法控制的代码的安全问题,你无法调试的代码的实际问题等等。但更重要的原因一般来说,你不需要使用它。Python向程序员公开了很多内部机制,你很少需要编写编写代码的代码。


查看完整回答
反对 回复 2019-05-22
  • 5 回答
  • 0 关注
  • 823 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信