【问题标题】:Use of eval in Python, MATLAB, etc [duplicate]在 Python、MATLAB 等中使用 eval [重复]
【发布时间】:2013-11-23 10:43:34
【问题描述】:

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

由于它以多种语言实现并且可能导致不良的编程风格,我认为它仍然可用是有原因的。

【问题讨论】:

  • 好问题。我有兴趣看到答案。
  • @InbarRose 我不同意。这个问题不是问“eval 的合法用途是什么”,而只是问“eval 的这种特定用途是否合法”。因此,答案说这种使用是不好的以及如何避免它,但不是什么时候应该使用。
  • 为什么问题从“在 Matlab 中使用 eval”变成了“Python”?
  • 修复了标题。也许有人不喜欢 Matlab。 Wikipedia page on eval 描述了几种用途。

标签: python matlab eval


【解决方案1】:

首先,这里是Mathwork's list of alternatives to eval

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

【讨论】:

  • +1 获取 Mathworks 链接!
  • 这实际上是一个不错的思路。但我不确定这个计数是否正确,因为它不是那样工作的。
【解决方案2】:

我发现合理使用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 让我允许用户传入他们想要的任意可调用对象。

关于为什么这适用于我的情况的几点说明:

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

  2. 用户应对其糟糕的 lambda 函数负责。我可以做一些验证 eval 在传递的谓词上工作,甚至可以即时创建一些测试或者有一个很好的失败模式,但最终我可以告诉他们提供是他们的工作有效的谓词,并确保可以使用简单的谓词来操作数据。如果没有这个约束,我就不得不为不同的系统脱壳。

  3. 这些参数文件的用户组成了一个小组,他们大多愿意遵守约定。如果这不是真的,那么人们会劫持谓词字段来做许多不恰当的事情,这将是有风险的——这将是难以防范的。在大型项目中,这不是一个好主意。

我不知道我的观点是否普遍适用,但我想说,如果你能保证你的用户是一小群公约支持者(一种罕见的壮举,我知道)。

【讨论】:

    【解决方案3】:

    在 MATLAB 中,当函数通过 inputname 函数使用输入参数的名称时,eval 函数非常有用。例如,要重载内置的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,那么在处理在命令窗口中显示有用信息的封闭源代码时它非常强大,您需要捕获并解析该输出。

    【讨论】:

      猜你喜欢
      • 2018-08-13
      • 2021-03-13
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      • 2012-09-27
      • 1970-01-01
      • 2011-01-28
      • 1970-01-01
      相关资源
      最近更新 更多