Nargin против существующего - PullRequest
12 голосов
/ 09 апреля 2009

С учетом такой функции, как:

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

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

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

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

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

Есть какие-нибудь мысли по этому вопросу?

Ответы [ 6 ]

10 голосов
/ 09 апреля 2009

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

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

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

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

  myparam = defaultvalue;

elseif

  ...

end

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

7 голосов
/ 09 апреля 2009

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

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

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

4 голосов
/ 09 апреля 2009

Я бы выбрал опцию NARGIN , по причинам, указанным SCFrench . Еще одно преимущество: я часто использую его в сочетании с оператором SWITCH , когда у меня более 2 входных аргументов:

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 голосов
/ 09 апреля 2009

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

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

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

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

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

3 голосов
/ 22 августа 2011

Для тех, кто использует 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
2 голосов
/ 29 ноября 2016

Я настоятельно предпочитаю 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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...