在Python,MATLAB等中使用eval

Use of eval in Python, MATLAB, etc

本问题已经有最佳答案,请猛点这里访问。

我知道人们不应该使用eval。出于所有明显的原因(性能、可维护性等)。我的问题更多的是站在一边——它有合法的用途吗?应该使用它而不是以另一种方式实现代码。

因为它是用几种语言实现的,并且可能导致糟糕的编程风格,所以我认为它仍然可用是有原因的。


首先,这里是MathWork的Eval备选方案列表。

您也可以很聪明,在编译后的应用程序中使用eval()来构建mcode解释器,但是matlab编译器不允许这样做,原因很明显。


在matlab中,当函数通过inputname函数使用输入参数的名称时,eval函数非常有用。例如,要重载内置的display函数(对输入参数的名称敏感),需要eval函数。例如,要从过载的display调用内置的display,您可以这样做

1
2
3
4
function display(X)
    eval([inputname(1), ' = X;']);
    eval(['builtin(''display'', ', inputname(1), ');']);
end

在matlab中也有evalc。从文档中:

T = evalc(S) is the same as EVAL(S) except that anything that would
normally be written to the command window, except for error messages,
is captured and returned in the character array T (lines in T are
separated by '
' characters).

如果您仍然考虑这个eval,那么它在处理在命令窗口中显示有用信息的关闭源代码时非常强大,您需要捕获和分析该输出。


我发现合理使用eval的一个地方是获取小的代码谓词,我的软件使用者需要能够提供这些谓词作为参数文件的一部分。

例如,可能有一个名为"data"的项,它有一个读写数据的位置,但也需要在加载时对其应用一些谓词。在yaml文件中,这可能看起来像:

1
2
3
4
5
Data:
    Name: CustomerID
    ReadLoc: some_server.some_table
    WriteLoc: write_server.write_table
    Predicate:"lambda x: x[:4]"

在从yaml加载和分析对象时,我可以使用eval将谓词字符串转换为可调用lambda函数。在这种情况下,它意味着customerid是一个长字符串,在这个特定的实例中只需要前四个字符。

yaml提供了一些笨拙的方法来神奇地调用对象构造函数(例如,在上面的代码中使用类似于!Data的东西,然后在代码中为Data定义了一个类,该类适当地使用yaml钩住构造函数)。事实上,我对yaml magic object结构最大的批评之一是它实际上就像把整个参数文件变成一个巨大的eval语句。如果您需要验证问题,并且在代码的多个部分吸收参数文件的多个部分的方式上需要灵活性,那么这是非常有问题的。它也不适合使用Mako轻松地进行模板化,而我上面的方法使这变得容易。

我认为这种可以用任何XML工具轻松解析的简单设计更好,并且使用eval允许用户传递他们想要的任意可调用的内容。

关于我的案例中为什么这样做:

  • 代码的用户不是Python程序员。他们没有能力编写自己的函数,然后只传递一个模块位置、函数名和参数签名(不过,将所有这些都放在参数文件中是解决这一问题的另一种方法,如果用户可以信任地编写代码,则不依赖于eval)。

  • 用户对其糟糕的lambda函数负责。我可以验证eval在通过的谓词上工作,甚至可以动态地创建一些测试,或者具有良好的失败模式,但是在一天结束的时候,我可以告诉他们提供有效的谓词并确保数据可以用简单的谓词操作是他们的工作。如果这个限制没有到位,我就得把它换成一个不同的系统。

  • 这些参数文件的用户组成了一个小组,大多数人都愿意遵守约定。如果这不是真的,那么人们会很危险地打招呼谓词字段来做许多不适当的事情——这很难防范。在大项目上,这不是一个好主意。

  • 我不知道我的观点是否适用于一般情况,但我想说,如果你能保证你的用户是一小群惯例拥护者(我知道这是一个罕见的壮举),那么使用eval来增加参数文件的灵活性是很好的。