等效于evalin,不需要输出参数(内部)

时间:2019-04-18 11:27:00

标签: matlab environment

背景知识-我正在阅读有关访问阴影函数的信息,并开始使用builtin。我写了一个小函数:

function klear(x)
%  go to parent environment...
evalin('base', builtin('clear','x')) ;  
end

这会引发错误:

Error using clear
Too many output arguments.

我认为发生这种情况是因为evalin要求从所馈送的内容中获取任何输出,但是clear是没有返回值的函数之一。
有两个问题:我是否正确地解释了这个问题;如果是,是否有替代函数可以让我在父环境中执行一个函数(不需要输出)?

注意:我完全知道反对尝试访问带阴影的函数(或者避免以重载基本函数等方式命名函数)的论点。这主要是一个问题,可以帮助我了解MATLAB中可以做什么和不能做什么。

注释2

我最初的目标是编写一个需要输入参数的重载函数,以避免clear的恶意行为,该行为默认为删除所有内容。在Q&D伪代码中,

function clear(x)
if ~exist('x','var') return
execute_in_base_env(builtin(clear(x)))
end

2 个答案:

答案 0 :(得分:2)

代码中会发生什么:

evalin('base', builtin('clear','x'));

builtin是在当前上下文中求值的,并且因为它用作evalin的参数,所以预期会产生输出。完全相同:

ans = builtin('clear','x');
evalin('base',ans);

您看到的错误消息出现在这两行代码的第一行,而不是第二行。并不是因为evalin确实支持不产生输出参数的调用语句。

evalin需要一个字符串来求值。您需要构建以下字符串:

str = 'builtin(''clear'',''x'')';
evalin('base',ans);

(在MATLAB中,将引号字符加倍即可将其转义。)

您的功能将如下所示:

function clear(var)
try
    evalin('base',['builtin(''clear'',''',var,''')'])
catch
    % ignore error
end
end

(以这种方式将一个字符串插入另一个字符串相当尴尬,这是我不喜欢eval和朋友的众多原因之一。)

在这种情况下,最好使用evalin('caller',...),这样,当您从函数中调用新的clear时,它将删除函数工作区中的某些内容,而不是基本工作区中的某些内容。我认为'base'仅应在可控制用户工作区中变量的GUI中使用,而不应从可以在任何地方调用且应被期望(在这种情况下使用其名称)可以在本地执行的功能中使用


有某些理由可能使它真正有用,但是总的来说,您应该尽量避免使用clear,就像使用eval和朋友一样。 clear会降低程序执行速度。 (在用户和MATLAB JIT上)将一个空数组分配给变量以从内存中删除其内容要容易得多(如rahnema1 in a comment所建议。如果您还使用function:编写函数,而不是脚本!

答案 1 :(得分:2)

您的clear覆盖有几个问题:

  • 无论从何处调用它,它将始终clear在基本工作区中。
  • 它不支持多个输入,这是很常见的用例。

相反,我会检查它是否从基本工作区中调用,并以特殊情况检查它是否清除了所有内容。如果某个函数正在调用普通clear来清除其所有变量,那是不好的做法,但这仍然是该函数逻辑的工作方式,并且您不想破坏它。否则可能会出错,或更糟的是,返回错误的结果。

所以,像这样:

function clear(varargin)
  stk = dbstack;
  if numel(stk) == 1 && (nargin == 0 || ismember('all', varargin))
    fprintf('clear: balking at clearing all vars in base workspace. Nothing cleared.\n');
    return;
  end

  % Check for quoting problems
  for i = 1:numel(varargin)
    if any(varargin{i} == '''')
      error('You have a quote in one of your args. That''s not valid.');
    end
  end
  % Construct a clear() call that works with evalin()
  arg_strs = strcat('''', varargin, '''');
  arg_strs = [{'''clear'''} arg_strs];
  expr = ['builtin(' strjoin(arg_strs, ', '), ')'];
  % Do it
  evalin('caller', expr);
end

我希望不言而喻,这是我不建议在实践中使用的骇人听闻的技巧。 :)