我正在使用以下课程轻松存储我的歌曲数据 .
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
似乎被认为是一种不良做法,使用起来不安全 . 如果是这样,任何人都可以向我解释为什么,并告诉我一个更好的方法来定义上述类?
8 回答
是的,使用eval是一种不好的做法 . 仅举几个原因:
几乎总有一种更好的方法
非常危险和不安全
使调试变得困难
慢
在您的情况下,您可以使用setattr代替:
EDIT:
在某些情况下,您必须使用eval或exec . 但它们很少见 . 在你的情况下使用eval肯定是一个坏习惯 . 我强调不好的做法,因为eval和exec经常在错误的地方使用 .
EDIT 2:
看起来有些人不同意在OP情况下,eval“非常危险且不安全” . 对于这个特定情况可能也是如此,但一般情况下并非如此 . 这个问题很笼统,我列出的理由也适用于一般情况 .
EDIT 3: 重新排序第1点和第4点
使用
eval
很弱,不是一个明显不好的做法 .它违反了"Fundamental Principle of Software" . 您的来源不是可执行文件的总和 . 除了你的来源,还有
eval
的参数,必须清楚地理解 . 因此,它是最后的工具 .这通常是轻率设计的标志 . 动态源代码很少有充分的理由,即时构建 . 使用委托和其他OO设计技术几乎可以做任何事情 .
导致小块代码的动态编译速度相对较慢 . 通过使用更好的设计模式可以避免开销 .
作为一个脚注,在疯狂的反社会人士的手中,它可能不会很好 . 然而,当遇到疯狂的反社会用户或管理员时,最好不要首先给他们解释Python . 在真正邪恶的手中,Python可以承担责任;
eval
根本不会增加风险 .在这种情况下,是的 . 代替
你应该使用builtin函数
setattr
:是的:
使用Python的Hack:
以下代码将列出在Windows计算机上运行的所有任务 .
在Linux中:
值得注意的是,对于有问题的具体问题,有几种方法可以使用
eval
:如上所述,最简单的是使用
setattr
:一种不太明显的方法是直接更新对象的
__dict__
对象 . 如果您要做的只是将属性初始化为None
,那么这不如上面那么简单 . 但考虑一下:这允许您将关键字参数传递给构造函数,例如:
它还允许您更明确地使用
locals()
,例如:...并且,如果您真的想将
None
分配给名称在locals()
中找到的属性:为对象提供属性列表的默认值的另一种方法是定义类的
__getattr__
方法:当以正常方式找不到命名属性时,将调用此方法 . 这种方法比简单地在构造函数中设置属性或更新
__dict__
更简单,但它的优点是实际上不创建属性,除非它存在,这可以大大减少类的内存使用 .所有这一切:一般来说,有很多原因可以避免
eval
- 执行代码的安全问题,你不需要调试等等 . 但更重要的原因是,一般来说,你不需要用它 . Python向程序员公开了很多内部机制,你很少需要编写代码来编写代码 .其他用户指出如何更改代码,使其不依赖于
eval
;我将提供一个使用eval
的合法用例,即使在CPython中也可以找到它:测试 .这是我在test_unary.py中找到的一个例子,其中测试
(+|-|~)b'a'
是否引发TypeError
:这里的用法显然不错;您定义输入并仅观察行为 .
eval
非常适合测试 .Take a look at this search for
eval
,在CPython git存储库上执行;使用eval进行测试的用量很大 .当
eval()
用于处理用户提供的输入时,您启用用户Drop-to-REPL,提供如下内容:你可能会侥幸成功,但通常你不想在你的应用程序中使用arbitrary code execution的向量 .
除了@Nadia Alramli的答案之外,由于我是Python的新手并且急于检查使用
eval
将如何影响时间,我尝试了一个小程序,下面是观察结果: