我知道不应该使用eval
. 出于所有显而易见的原因(性能、可维护性等)。我的问题更多的是——它有合法用途吗?应该在哪里使用它而不是以另一种方式实现代码。
由于它以多种语言实现并且可能导致不良的编程风格,我认为它仍然可用是有原因的。
首先,这是Mathwork 的 eval 替代品列表。
你也可以很聪明,eval()
在编译的应用程序中使用来构建你的 mCode 解释器,但 Matlab 编译器不允许这样做,原因很明显。
我发现一个合理使用的地方eval
是获取我的软件的消费者需要能够作为参数文件的一部分提供的小的代码谓词。
例如,可能有一个名为“Data”的项目具有读取和写入数据的位置,但还需要在加载时对其应用一些谓词。在 Yaml 文件中,这可能如下所示:
Data:
Name: CustomerID
ReadLoc: some_server.some_table
WriteLoc: write_server.write_table
Predicate: "lambda x: x[:4]"
从 Yaml 加载和解析对象后,我可以使用eval
将谓词字符串转换为可调用的 lambda 函数。在这种情况下,这意味着 CustomerID 是一个长字符串,并且在此特定实例中只需要前 4 个字符。
Yaml 提供了一些笨拙的方法来神奇地调用对象构造函数(例如,!Data
在我上面的代码中使用类似的东西,然后在Data
代码中定义了一个类,以便在构造函数中适当地使用 Yaml 挂钩)。事实上,我对 Yaml 魔术对象构造的最大批评之一是它实际上就像将整个参数文件变成一个巨大的eval
语句。如果您需要验证事物并且需要灵活地让代码的多个部分吸收参数文件的多个部分,那么这是非常有问题的。它也不适合使用 Mako 进行模板化,而我上面的方法很容易。
我认为这种可以使用任何 XML 工具轻松解析的更简单的设计更好,并且使用eval
让我允许用户传入他们想要的任意可调用对象。
关于为什么这适用于我的情况的几点说明:
代码的用户不是 Python 程序员。他们没有能力编写自己的函数,然后只传递模块位置、函数名称和参数签名(尽管将所有这些都放在参数文件中是解决此问题的另一种方法,eval
如果可以信任消费者编写代码。)
用户应对他们糟糕的 lambda 函数负责。我可以对通过的谓词进行一些验证,eval
甚至可以即时创建一些测试或有一个很好的故障模式,但最终我可以告诉他们提供有效的谓词是他们的工作和以确保可以使用简单的谓词来操作数据。如果这个约束没有到位,我将不得不为不同的系统脱壳。
这些参数文件的用户组成了一个最愿意遵守约定的小组。如果这不是真的,那么人们会劫持谓词字段来做许多不恰当的事情,这将是有风险的——这将是难以防范的。在大型项目中,这不是一个好主意。
我不知道我的观点是否普遍适用,但我会说,eval
如果你能保证你的用户是一小群公约支持者(我知道这是一个罕见的壮举),那么使用来增加参数文件的灵活性是很好的。
在 MATLAB 中,eval
当函数通过函数使用输入参数的名称时,该函数很有用inputname
。例如,要重载内置display
函数(它对输入参数的名称敏感),该eval
函数是必需的。例如,display
要从重载中调用内置函数display
,您可以这样做
function display(X)
eval([inputname(1), ' = X;']);
eval(['builtin(''display'', ', inputname(1), ');']);
end
在 MATLAB 中也有evalc
. 从文档中:
T = evalc(S) 与 EVAL(S) 相同,只是通常会写入命令窗口的任何内容(错误消息除外)都会被捕获并在字符数组 T 中返回(T 中的行由 '\ n' 个字符)。
如果您仍然考虑这一点eval
,那么在处理在命令窗口中显示有用信息并且您需要捕获和解析该输出的封闭源代码时,它非常强大。