nargin vs exists

时间:2009-04-09 10:31:41

标签: matlab

给出如下函数:

function foo(myParam)
if nargin<1
  myParam = 'default value';
end % if
end % function

我见过人们使用类似下面的内容来代替nargin版本

if ~exist('myParam', 'var')
  myParam = 'default value';
end %if

我想知道是否有任何偏好?

“〜exists ...”版本给我带来的好处是,如果我改变我的函数参数的顺序,那么它应该仍然有效。然而,我对这种方法的关注是,在嵌套函数的情况下,我可能会无意中拾取全局定义的变量或周围函数的范围。

关于这个问题的任何想法?

6 个答案:

答案 0 :(得分:10)

两者都应该有用。但...

存在往往很慢,因为它必须通过工作区查看相关变量。当你编写这样的错误检查时,你不希望它们吸收CPU周期。针对nargin的测试是针对单个数值的简单测试。

我通常也建议进行更广泛的测试。像

这样的东西
if (nargin<1) || isempty(myparam)

  myparam = defaultvalue;

elseif

  ...

end

在elseif分支中,我将放置一组额外的测试,以查看参数是否具有预期的大小,形状,变量类等。如果这些测试失败,我将返回一条友好的错误消息,解释出了什么问题。

答案 1 :(得分:7)

我会使用nargin有两个原因:

  1. 如果您更改函数的参数顺序,修复输入检查代码将是您遇到的问题中最少的;您还必须将所有呼叫站点更新到您的功能。

  2. nargin便宜得多。存在,即使只是检查变量,也必须扫描整个工作区,沿途进行一系列字符串比较。 nargin方法只包含一个标量小于操作。

答案 2 :(得分:4)

我总是使用nargchk验证参数,然后按照您的nargin测试进行验证。正如其他人指出的那样,它们更便宜,我认为更清楚。

在我期望重复使用的函数中,我总是预先进行大量检查,然后构造代码以便稍后调用实际的实现。

我也倾向于构造可选参数(当不使用varargin时),如下所示:

function x = myfcn( arg1, opt_arg2 )
if nargin < 2
   arg2 = 'default';
else
   arg2 = opt_arg2;
end

因为我认为这在编辑文件时更加明显,哪些参数应该是可选的。

答案 3 :(得分:4)

由于NARGIN列出的原因,我选择SCFrench选项。另一个好处是:当我有超过2个输入参数时,我经常发现自己将它与SWITCH语句结合使用:

function outArgs = my_fcn(inArg1,inArg2,inArg3)
  switch nargin,
    case 0,  % No input case
      error('Not enough inputs!');
    case 1,  % Set last 2 inputs to default
      inArg2 = 'yes';
      inArg3 = 'on';
    case 2,  % Set last input to default
      inArg3 = 'on';
  end
  ...
  % Checking of variable types and values would go here! 
  ...
end

答案 4 :(得分:3)

对于那些使用MATLAB R2007b或更高版本的人,这里有一个更好的答案:InputParser

它省去了必须同步参数的任何添加,删除,重命名和重新排序的麻烦。

(你保存多少取决于你的编码风格,但是没有比InputParser更简洁的方法。)

我没有测试它的速度,但是如果你的功能运行时间超过1000毫秒,那么没有理由担心InputParser的速度。

示例:

function AbCdEfGhIj(ffff, ggggg, varargin)
opts = inputParser;
opts.addRequired('ffff', @(p)(ischar(p) && size(p,1)==1 || iscell(p)));
opts.addRequired('ggggg', @(p)(iscell(p) && all(cellfun(@ischar,p))));
opts.addOptional('Recursive', false, @islogical);
opts.addOptional('IncludeFullPath', logical([]), @islogical);
opts.parse(ffff, ggggg, varargin{:});
opts = opts.Results;
if isempty(opts.IncludeFullPath),
    opts.IncludeFullPath = iscell(opts.fffff) || opts.Recursive;
end

答案 5 :(得分:2)

由于两个原因,我强烈希望exist超过nargin选项。

<强> 1 在从那些从未被教过回顾自己的代码的人那里阅读了大量代码之后,我对此感到更加强烈,因为exist使代码可读。 例如,我曾经遇到过这样的函数。为方便起见,我给出了变量合理的名称:

[model, accuracy] = epicModelingFunction (dataMatrix, responseVector, indicatorForCategoricalVariables, optionsForInternalFunctions, typeOfDistanceCalculation, notationForMissingValues, isClassificationAndNotRegression, scalingMethod, shouldPlotAllIntermediateStuff)
% EPICMODELINGFUNCTION is actually a horrible function to read and not epic at all
% ...

然后,除了前两个变量之外,每个变量都跟if nargin < n。我可以在不计算标题输入的情况下遵循nargin(n)应该是什么的唯一原因是if nargin < n始终跟随(有时只有几行代码)并且缺少输入的声明默认值。对于if nargin < n中更大的代码,我肯定会失去踪迹。

2。 exist如果从函数调用,则无法真正检查完整的工作区。当然,比较两个数字比较少数字符串要便宜,但如果在函数的开头用它来填充未给定参数的默认值,那就没问题了。考虑以下功能:

function testExist(C)
if exist('B', 'var')
    disp('''exist'' in a function checks the workspace.')
elseif exist('C', 'var')
    disp('''exist'' in a function ignores the variables in the workspace, but checks the function space.')
else
    disp('''exist'' is broken or no parameter was given.')
end
end

然后执行以下操作:

A = magic(3);
B = magic(4);
testExist(A)

导致此输出:

'exist' in a function ignores the variables in the workspace, but checks the function space.