Подтвердить что ты не робот

Наргин против существует

Для такой функции, как:

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

Я видел, что вместо версии nargin люди использовали что-то вроде следующего:

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

Мне интересно, есть ли какие-либо предпочтения в любом случае?

Версия "~ exist..." для меня имеет то преимущество, что если я изменю порядок параметров моей функции, она должна работать. Однако моя озабоченность этим подходом заключается в том, что я могу случайно перехватить переменные, которые определены глобально или в пределах окружения в случае вложенных функций.

Любые мысли по этому вопросу?

4b9b3361

Ответ 1

Оба должны работать. Но...

Exist имеет тенденцию быть медленным, так как он должен просматривать ваше рабочее пространство для рассматриваемой переменной. Когда вы пишете ошибки проверки, как это, вы не хотите, чтобы они всасывали циклы процессора. Тест против наргина - это простой тест против единственного числового значения.

Я бы также предложил более обширный тест. Что-то вроде

if (nargin<1) || isempty(myparam)

  myparam = defaultvalue;

elseif

  ...

end

Внутри ветки elseif я положу набор дополнительных тестов, чтобы увидеть, есть ли у параметра ожидаемый размер, форма, класс переменной и т.д. Если эти тесты терпят неудачу, я верну приветственное сообщение об ошибке, которое объясняет что не так.

Ответ 2

Я пошел бы с наргином по двум причинам:

  • Если вы измените порядок параметров на свою функцию, исправление кода проверки ввода будет наименьшим из ваших проблем; вам также придется обновлять все сайты вызовов до вашей функции.

  • Наргин намного дешевле. существуют, даже если они ограничены, чтобы просто проверять переменные, необходимо отсканировать всю рабочую область, выполняя ряд сравнений строк на этом пути. метод наргина состоит только из скаляра, меньшего чем операция.

Ответ 3

Я всегда проверяю аргументы с помощью nargchk, а затем перехожу с тегами nargin, как и они. Как отмечали другие, они дешевле, и я думаю, что яснее.

В функциях, которые, как я ожидаю, будут повторно использоваться в значительной степени, я всегда ставил перед собой много проверок, а затем структурировал код для вызова реальной реализации позже.

Я также склонен структурировать необязательные аргументы (если не использовать varargin) следующим образом:

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

как я думаю, это делает его более очевидным при редактировании файла, аргументы которого будут необязательными.

Ответ 4

Я бы пошел с опцией NARGIN по причинам, указанным SCFrench. Еще одно преимущество: я часто использую его в сочетании с выражением 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

Ответ 5

Для тех, кто использует 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

Ответ 6

Я предпочитаю 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.