我已经表明性能str2func更好,但我得到了很多评论,说明有更多根本原因不使用eval.哪些基本原因适用于以下情况eval并且不适用于str2func以下情况:
f='a^x+exp(b)+sin(c*x)+d'
Run Code Online (Sandbox Code Playgroud)
eval:
y = eval(f)
Run Code Online (Sandbox Code Playgroud)
或(rahnema1建议)
fHandle = eval(['@(x, a, b, c, d) ' f]);
y = fHandle(x, a, b, c, d);
Run Code Online (Sandbox Code Playgroud)str2func:
fHandle = str2func(['@(x, a, b, c, d) ' f]);
y = fHandle(x, a, b, c, d);
Run Code Online (Sandbox Code Playgroud)除性能原因外,为什么第一个选项比第二个选项更差?
备注
请注意,我知道如果可能的话,最好避免使用这两种方法.
请注意,我将输出分配给eval变量,这样可以避免执行大量棘手的代码.
And*_*eak 10
不要试图淡化安全风险eval.如果您不完全控制输入,则运行任意代码可能会有害.如果您完全控制输入,几乎总有一种更好的方法不涉及动态代码生成.
你坚持一个具体的例子:
>> ls TMPFILE
Error using ls (line 35)
ls: cannot access 'TMPFILE': No such file or directory
>> y = eval('system(''touch TMPFILE'')');
>> y
y =
0
>> ls TMPFILE
TMPFILE
Run Code Online (Sandbox Code Playgroud)
touch是一个非常友好的unix命令; 它会创建一个空文件.想象一下rm -rf ~在相同的背景下.
让我们尝试一下str2func:
>> y = str2func('system(''touch TMPFILE2'')');
Warning: The input to STR2FUNC "system('touch TMPFILE2')" is not a valid function name. This will generate an error in a future release.
>> ls TMPFILE2
Error using ls (line 35)
ls: cannot access 'TMPFILE2': No such file or directory
>> y
y =
function_handle with value:
@system('touch TMPFILE2')
>> y()
Undefined function or variable 'system('touch TMPFILE2')'.
Run Code Online (Sandbox Code Playgroud)
旁注:虽然风险eval是真实的,而不仅仅是由于迷信,不使用eval并不一定意味着你是安全的.我最喜欢的例子,鬼鬼祟祟的魔鬼str2num:
>> x = str2num('[system(''touch TMPFILE3'')]')
x =
0
>> ls TMPFILE3
TMPFILE3
Run Code Online (Sandbox Code Playgroud)
所以,即使你没有明确使用eval,它可能发生,你正在使用一个方便的功能,而不是做.你应该总是确保不会发生这种情况:使用safe str2double代替str2num,而str2func不是使用eval(因为我们在上面看到它str2func 不会执行任意代码).
首先,性能(特别是x100较慢)应该是不使用某些东西的充分理由.
但是,你错过了这一点.您现在问"为什么不在eval评估字符串中的函数的具体示例中使用?".那么,答案就是因为你有一个函数被称为str2func专门更快,更安全地完成这项工作.你不应该使用eval的原因是因为在你想要使用eval的情况下,代码的逻辑是有缺陷的.
唯一的原因eval是评估一个不仅仅是字符串函数的任意输入(为什么你会这样做,你已经表明它有一个特定的函数).如果你知道你在评估什么,那么你不需要eval,你可以编写你期望的代码.因此,eval仅在您接受通用输入时使用.但通用输入包括rm -rf删除整个操作系统.或者在一个不那么灾难性的情况下,代码可能会重写一个对算法其余部分很重要的变量.很明显,为什么你不想让代码运行任意输入.
动态变量怎么样?一个可以使用生成的可怕想法eval.你可能会通过接受任意输入而意外地做到这一点.
但还有更多的事情.eval确实使你的代码不可读.在运行时之前,您不知道代码的作用.
我见过在其核心功能中执行此操作的代码
model.solve_algorithm=eval(['default(',[ class(input3) ],')']);
result=eval(model.solve_algorithm);
Run Code Online (Sandbox Code Playgroud)
代码做了什么?有什么选择?没有办法知道,除非你运行它,看看它去了哪里.这使代码变得模糊,难以阅读,并且当然难以维护.在代码中明确表示在代码的可维护性方面确实受益匪浅.
TLDR:在任何情况下,您可能想要使用eval,其中一个正在发生:
TL; DR - eval可以访问本地定义的函数,而str2func不是.在这两者中使用的"正确"功能取决于代码的结构.
在没有深入eval讨论整个"为什么是坏"的讨论的情况下,我将尝试着重于在您的问题的上下文中讨论它的相关MATLAB文档:
考虑一个包含两个函数的文件:
function out = q46213509
f='a^x+exp(b)+sin(c*x)+d';
fHandle = {eval(['@(x, a, b, c, d) ' f]), str2func(['@(x, a, b, c, d) ' f])};
out = [fHandle{1}(1,2,3,4,5) fHandle{2}(1,2,3,4,5)];
end
function e = exp(x)
e = x.^0./factorial(0) - x.^1./factorial(1) + x.^2./factorial(2); % Error is deliberate
end
Run Code Online (Sandbox Code Playgroud)
当您运行上述操作时,会导致:
ans =
8.7432 26.3287
Run Code Online (Sandbox Code Playgroud)
如果您正在使用类并且您定义了自己的运算符,这可能会失控...假设某人决定将文件添加到您的MATLAB路径中,并方便地为其指定您使用的某个函数的名称,或者一个可重载的运算符(即mpower.m):
function out = mpower(varargin)
% This function disregards all inputs and prints info about the calling workspace.
disp(struct2cell(evalin('caller','whos')));
end
Run Code Online (Sandbox Code Playgroud)
虽然在某些情况下,MATLAB可以防止重新定义内置函数,但我敢打赌,上面的场景可能会str2func让人感到困惑......
我暂时搁置两种方法的论点,尽管它们都非常有效,并且尽责的读者应该尝试理解它们.
我可以看到两个明显的差异.对于这些示例,我们必须假设您已经使用一些可变数据构造了脚本中函数的输入字符串,并假设它可能是任何内容(错误或其他).所以我们准备并解决最坏的情况.
str2func包括一些额外的检查,以确保您传递的是一个有效的功能,这可能会避免不必要的行为.让我们不要采取"是的但你可以这样做以避免这种情况"的立场,并看一个例子......
% Not assigning an output variable
% STR2FUNC: You've harmlessly assigned ans to some junk function
str2func('delete test.txt')
% EVAL: You've just deleted your super important document
eval('delete test.txt')
% Assigning an output variable
% STR2FUNC: You get a clear warning that this is not a valid function
f = str2func('delete test.txt')
% EVAL: You can a non-descript error "Unexpected MATLAB expression"
f = eval('delete test.txt')
Run Code Online (Sandbox Code Playgroud)另一个区别是大约一半str2func文档的主题.它涉及变量范围,可在"检查str2func和之间的差异eval" 标题下找到.
[函数简介]
如果使用匿名函数的字符向量表示,则生成的函数句柄无法访问私有或本地函数.
[检查之间的差异str2func和eval]
当str2func一个与表示对匿名函数的特征向量使用,它没有访问本地函数[...].该eval函数可以访问本地函数.
总而言之,您可能有一些用例,其中每个函数都是可取的,具体取决于您所需的错误处理和变量作用域应该永远不会使用eval或str2func尽可能使用,如其他答案中所述.