为什么使用“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
的属性)而不产生这种风险?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
是的,使用
eval
是一种不好的做法。仅举几个原因:在您的情况下,您可以使用 setattr 代替:
在某些情况下,您必须使用
eval
或exec
。但它们很罕见。在您的情况下使用eval
肯定是一种不好的做法。我强调不好的做法,因为eval
和exec
经常被用在错误的地方。回复评论:
看起来有些人不同意
eval
在OP案例中“非常危险且不安全”。对于这个具体案例来说,这可能是正确的,但一般情况下并非如此。这个问题很普遍,我列出的原因也适用于一般情况。Yes, using
eval
is a bad practice. Just to name a few reasons:In your case you can use setattr instead:
There are some cases where you have to use
eval
orexec
. But they are rare. Usingeval
in your case is a bad practice for sure. I'm emphasizing on bad practice becauseeval
andexec
are frequently used in the wrong place.Replying to the comments:
It looks like some disagree that
eval
is 'very dangerous and insecure' in the OP case. That might be true for this specific case but not in general. The question was general and the reasons I listed are true for the general case as well.使用
eval
很弱,但显然并不是一个坏的做法。它违反了“软件基本原则”。您的源代码并不是可执行文件的总和。除了您的来源之外,还有
eval
的参数,必须清楚地理解。因此,它是最后的手段。这通常是设计不周全的标志。动态构建的动态源代码很少有充分的理由。几乎任何事情都可以通过委托和其他面向对象设计技术来完成。
它会导致小段代码的动态编译速度相对较慢。通过使用更好的设计模式可以避免这种开销。
作为脚注,在精神错乱的反社会者手中,它可能效果不佳。然而,当面对精神错乱的反社会用户或管理员时,最好一开始就不要给他们解释的 Python。在真正邪恶的人手中,Python 可能会成为一种负担;
eval
根本不会增加风险。Using
eval
is weak, not a clearly bad practice.It violates the "Fundamental Principle of Software". Your source is not the sum total of what's executable. In addition to your source, there are the arguments to
eval
, which must be clearly understood. For this reason, it's the tool of last resort.It's usually a sign of thoughtless design. There's rarely a good reason for dynamic source code, built on-the-fly. Almost anything can be done with delegation and other OO design techniques.
It leads to relatively slow on-the-fly compilation of small pieces of code. An overhead which can be avoided by using better design patterns.
As a footnote, in the hands of deranged sociopaths, it may not work out well. However, when confronted with deranged sociopathic users or administrators, it's best to not give them interpreted Python in the first place. In the hands of the truly evil, Python can a liability;
eval
doesn't increase the risk at all.是的,它是:
Hack using Python:
下面的代码将列出 Windows 计算机上运行的所有任务。
在Linux中:
Yes, it is:
Hack using Python:
The below code will list all tasks running on a Windows machine.
In Linux:
在这种情况下,是的。相反,
您应该使用 内置 函数
setattr
:In this case, yes. Instead of
you should use the builtin function
setattr
:值得注意的是,对于所讨论的具体问题,有几种使用
eval
的替代方法:如前所述,最简单的是使用
setattr
:一种不太明显的方法是更新直接对象的
__dict__
对象。如果您只想将属性初始化为None
,那么这比上面的要简单。但请考虑一下:这允许您将关键字参数传递给构造函数,例如:
它还允许您更明确地使用
locals()
,例如:...并且,如果您确实想要将
None
分配给在locals()
中找到名称的属性:为对象提供属性列表默认值的另一种方法是定义类的
>__getattr__
方法:当以正常方式找不到指定属性时,将调用此方法。这种方法比简单地在构造函数中设置属性或更新 __dict__ 稍微不那么简单,但它的优点是除非属性存在,否则不会实际创建该属性,这可以大大减少类的内存使用量。
这一切的要点是:一般来说,避免 eval 的原因有很多 - 执行您无法控制的代码的安全问题,您无法调试的代码的实际问题,但更重要的原因是,一般情况下,你不需要使用它。 Python 向程序员公开了如此多的内部机制,以至于您很少真正需要编写用于编写代码的代码。
It's worth noting that for the specific problem in question, there are several alternatives to using
eval
:The simplest, as noted, is using
setattr
:A less obvious approach is updating the object's
__dict__
object directly. If all you want to do is initialize the attributes toNone
, then this is less straightforward than the above. But consider this:This allows you to pass keyword arguments to the constructor, e.g.:
It also allows you to make your use of
locals()
more explicit, e.g.:...and, if you really want to assign
None
to the attributes whose names are found inlocals()
:Another approach to providing an object with default values for a list of attributes is to define the class's
__getattr__
method:This method gets called when the named attribute isn't found in the normal way. This approach somewhat less straightforward than simply setting the attributes in the constructor or updating the
__dict__
, but it has the merit of not actually creating the attribute unless it exists, which can pretty substantially reduce the class's memory usage.The point of all this: There are lots of reasons, in general, to avoid
eval
- the security problem of executing code that you don't control, the practical problem of code you can't debug, etc. But an even more important reason is that generally, you don't need to use it. Python exposes so much of its internal mechanisms to the programmer that you rarely really need to write code that writes code.其他用户指出如何更改您的代码以不依赖于
eval
;我将提供一个使用eval
的合法用例,该用例甚至在 CPython 中也能找到:测试。这是我在
test_unary.py< 中找到的一个示例/code>
其中测试
(+|-|~)b'a'
是否引发TypeError
:这里的用法显然不是坏习惯; 您定义输入并仅观察行为。
eval
对于测试来说很方便。看看在 CPython git 存储库上执行的对
eval
的搜索; eval 测试被大量使用。Other users pointed out how your code can be changed as to not depend on
eval
; I'll offer a legitimate use-case for usingeval
, one that is found even in CPython: testing.Here's one example I found in
test_unary.py
where a test on whether(+|-|~)b'a'
raises aTypeError
:The usage is clearly not bad practice here; you define the input and merely observe behavior.
eval
is handy for testing.Take a look at this search for
eval
, performed on the CPython git repository; testing with eval is heavily used.当使用
eval()
处理用户提供的输入时,您使用户能够Drop-to-REPL 提供类似这样的内容:您可能会侥幸逃脱,但通常您不需要 在您的应用程序中任意执行代码。
When
eval()
is used to process user-provided input, you enable the user to Drop-to-REPL providing something like this:You may get away with it, but normally you don't want vectors for arbitrary code execution in your applications.
除了 @Nadia Alramli 的回答之外,由于我是 Python 新手,并且渴望检查使用
eval
将如何影响 timings,我尝试了一个小程序,下面是观察结果:In addition to @Nadia Alramli answer, since I am new to Python and was eager to check how using
eval
will affect the timings, I tried a small program and below were the observations:只是不要在用户可以控制输入的地方使用 eval,因为如果类型:
他们将擦除您的整个电脑。如果你使用Linux。
Just do not use eval where the user can control the input because if the type:
They will erase your entire pc. If you use Linux.