Как установить значения по умолчанию для параметров функций в Matlab?

возможно ли иметь аргументы по умолчанию в Matlab? Например, здесь:

function wave(a, b, n, k, T, f, flag, fTrue=inline('0'))

Я хотел бы, чтобы истинное решение было необязательным аргументом для волновой функции. Если это возможно, может кто-нибудь продемонстрировать правильный способ сделать это? В настоящее время я пытаюсь то, что я опубликовал выше, и я получаю:

??? Error: File: wave.m Line: 1 Column: 37
The expression to the left of the equals sign is not a valid target for an assignment.

16 ответов


нет прямого способа сделать это, как вы пытались.

обычный подход-использовать "varargs" и проверять количество аргументов. Что-то вроде:

function f(arg1, arg2, arg3)

  if nargin < 3
    arg3 =   'some default'
  end

end

есть несколько причудливых вещей, которые вы можете сделать с isempty, etc., и вы можете посмотреть на Matlab central для некоторых пакетов, которые связывают такие вещи.

вы могли бы взглянуть на varargin, nargchk, etc. Это полезные функции для такого рода вещей. с varargs позвольте вам оставить переменное количество конечных аргументов, но это не поможет вам обойти проблему значений по умолчанию для некоторых/всех из них.


я использовал inputParser объект для работы с настройкой параметров по умолчанию. Matlab не примет python-подобный формат, указанный в вопросе, но вы должны иметь возможность вызвать функцию следующим образом:

wave(a,b,n,k,T,f,flag,'fTrue',inline('0'))

после определения такой:

function wave(a,b,n,k,T,f,flag,varargin)

i_p = inputParser;
i_p.FunctionName = 'WAVE';

i_p.addRequired('a',@isnumeric);
i_p.addRequired('b',@isnumeric);
i_p.addRequired('n',@isnumeric);
i_p.addRequired('k',@isnumeric);
i_p.addRequired('T',@isnumeric);
i_p.addRequired('f',@isnumeric);
i_p.addRequired('flag',@isnumeric); 
i_p.addOptional('ftrue',inline('0'),1);    

i_p.parse(a,b,n,k,T,f,flag,varargin{:});

теперь значения, переданные в функцию, доступны через i_p.Results. Кроме того, я не был уверен, как проверить, что параметр передан для ftrue было на самом деле inline функция так оставила валидатор пустым.


еще один немного менее хакерский способ -

function output = fun(input)
   if ~exist('input','var'), input='BlahBlahBlah'; end
   ...
end

Да, было бы неплохо иметь возможность делать то, что вы написали. Но это невозможно в MATLAB. Многие из моих утилит, которые позволяют по умолчанию для аргументов, как правило, записываются с явными проверками в начале, как это:

if (nargin<3) or isempty(myParameterName)
  MyParameterName = defaultValue;
elseif (.... tests for non-validity of the value actually provided ...)
  error('The sky is falling!')
end

Ok, поэтому я обычно применяю лучшее, более описательное сообщение об ошибке. См., что проверка пустой переменной позволяет пользователю передать пустую пару скобок, [], в качестве заполнителя для переменной, которая будет принимать его значение по умолчанию. Однако автор должен предоставить код, чтобы заменить этот пустой аргумент значением по умолчанию.

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

в качестве средства для работы с этими парами свойств / значений вам нужно будет узнайте о varargin, как способ ввода полностью переменного числа аргументов в функцию. Я написал (и разместил) утилиту для работы с такими парами свойств / значений,parse_pv_pairs.м. Это поможет вам преобразовать пары свойств / значений в структуру matlab. Она также позволяет указать значения по умолчанию для каждого параметра. Преобразование громоздкого списка параметров в структуру-очень хороший способ передать их в MATLAB.


Это мой простой способ, чтобы установить значения по умолчанию для функции "попробуй":

function z = myfun (a,varargin)

%% Default values
b = 1;
c = 1;
d = 1;
e = 1;

try 
    b = varargin{1};
    c = varargin{2};
    d = varargin{3};
    e = varargin{4};
end

%% Calculation
z = a * b * c * d * e ;
end

С уважением!


Я обнаружил, что parseArgs функция может быть очень полезной.


существует также "хак", который можно использовать, хотя он может быть удален из matlab в какой-то момент: Функция eval принимает два аргумента из которых второй выполняется, если произошла ошибка с первым.

таким образом, мы можем использовать

function output = fun(input)
   eval('input;', 'input = 1;');
   ...
end

использовать значение 1 по умолчанию для аргумента


Я считаю, что нашел довольно изящный способ справиться с этой проблемой, занимая только три строки кода (запрет обертывания строк). Следующее поднимается непосредственно из функции, которую я пишу, и, похоже, работает по желанию:

defaults = {50/6,3,true,false,[375,20,50,0]}; %set all defaults
defaults(1:nargin-numberForcedParameters) = varargin; %overload with function input
[sigma,shifts,applyDifference,loop,weights] = ...
     defaults{:}; %unfold the cell struct

просто подумал, что поделюсь.


Я смущен, что никто не указал этот блог Лорен, один из разработчиков Matlab. Подход основан на varargin и избегает всех этих бесконечных и болезненных if-then-else или switch случаи с запутанными условиями. Когда есть немного значения по умолчанию, эффект эмо. Вот пример из связанного блог:

function y = somefun2Alt(a,b,varargin)
% Some function that requires 2 inputs and has some optional inputs.

% only want 3 optional inputs at most
numvarargs = length(varargin);
if numvarargs > 3
    error('myfuns:somefun2Alt:TooManyInputs', ...
        'requires at most 3 optional inputs');
end

% set defaults for optional inputs
optargs = {eps 17 @magic};

% now put these defaults into the valuesToUse cell array, 
% and overwrite the ones specified in varargin.
optargs(1:numvarargs) = varargin;
% or ...
% [optargs{1:numvarargs}] = varargin{:};

% Place optional args in memorable variable names
[tol, mynum, func] = optargs{:};

если вы все еще не поняли, попробуйте прочитать весь пост в блоге Лорен. У меня есть написано продолжение блоге что касается отсутствует позиционные значения по умолчанию. Я имею в виду, что вы могли бы написать что-то вроде:

somefun2Alt(a, b, '', 42)

и по-прежнему имеют значение по умолчанию eps значение


после осознания ASSIGNIN (спасибо ответ by b3) и ЕВАЛИН я написал две функции, чтобы, наконец, получить очень простую структуру вызова:

setParameterDefault('fTrue', inline('0'));

вот список:

function setParameterDefault(pname, defval)
% setParameterDefault(pname, defval)
% Author: Tobias Kienzler (https://stackoverflow.com/users/321973)
% sets the parameter NAMED pname to the value defval if it is undefined or
% empty

if ~isParameterDefined('pname')
    error('paramDef:noPname', 'No parameter name defined!');
elseif ~isvarname(pname)
    error('paramDef:pnameNotChar', 'pname is not a valid varname!');
elseif ~isParameterDefined('defval')
    error('paramDef:noDefval', ['No default value for ' pname ' defined!']);
end;

% isParameterNotDefined copy&pasted since evalin can't handle caller's
% caller...
if ~evalin('caller',  ['exist(''' pname ''', ''var'') && ~isempty(' pname ')'])
    callername = evalin('caller', 'mfilename');
    warnMsg = ['Setting ' pname ' to default value'];
    if isscalar(defval) || ischar(defval) || isvector(defval)
        warnMsg = [warnMsg ' (' num2str(defval) ')'];
    end;
    warnMsg = [warnMsg '!'];
    warning([callername ':paramDef:assigning'], warnMsg);
    assignin('caller', pname, defval);
end

и

function b = isParameterDefined(pname)
% b = isParameterDefined(pname)
% Author: Tobias Kienzler (https://stackoverflow.com/users/321973)
% returns true if a parameter NAMED pname exists in the caller's workspace
% and if it is not empty

b = evalin('caller',  ['exist(''' pname ''', ''var'') && ~isempty(' pname ')']) ;

Это более или менее снято с руководство Matlab; у меня только мимолетный опыт...

function my_output = wave ( a, b, n, k, T, f, flag, varargin )
  optargin = numel(varargin);
  fTrue = inline('0');
  if optargin > 0
    fTrue = varargin{1};
  end
  % code ...
end

Matlab не предоставляет механизм для этого, но вы можете построить его в коде userland, который является более терсером, чем inputParser или "if nargin

function varargout = getargs(args, defaults)
%GETARGS Parse function arguments, with defaults
%
% args is varargin from the caller. By convention, a [] means "use default".
% defaults (optional) is a cell vector of corresponding default values

if nargin < 2;  defaults = {}; end

varargout = cell(1, nargout);
for i = 1:nargout
    if numel(args) >= i && ~isequal(args{i}, [])
        varargout{i} = args{i};
    elseif numel(defaults) >= i
        varargout{i} = defaults{i};
    end
end

тогда вы можете вызвать его в своих функциях следующим образом:

function y = foo(varargin)
%FOO 
%
% y = foo(a, b, c, d, e, f, g)

[a, b,  c,       d, e, f, g] = getargs(varargin,...
{1, 14, 'dfltc'});

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

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


вы можете использовать в MATLAB; использование будет выглядеть так:

function output = wave(varargin);
% comments, etc
[reg, props] = parseparams(varargin);
ctrls = cell2struct(props(2:2:end),props(1:2:end),2);  %yes this is ugly!
a = reg{1};
b = reg{2};
%etc
fTrue = ctrl.fTrue;

function f(arg1, arg2, varargin)

arg3 = default3;
arg4 = default4;
% etc.

for ii = 1:length(varargin)/2
  if ~exist(varargin{2*ii-1})
    error(['unknown parameter: ' varargin{2*ii-1}]);
  end;
  eval([varargin{2*ii-1} '=' varargin{2*ii}]);
end;

например f(2,4,'c',3) вызывает параметр c быть 3.


если бы вы использовали октаву, вы могли бы сделать это так - но, к сожалению, matlab не поддерживает эту возможность

function hello (who = "World")
  printf ("Hello, %s!\n", who);
endfunction

(взято из doc)


мне нравится делать это несколько более объектно-ориентированным способом. Перед вызовом wave () сохраните некоторые из ваших аргументов в структуре, например. один из параметров называется:

parameters.flag =42;
parameters.fTrue =1;
wave(a,b,n,k,T,f,parameters);

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

function output = wave(a,b,n,k,T,f,parameters)
  flagDefault=18;
  fTrueDefault=0;
  if (isfield(parameters,'flag') == 0 || isempty(parameters.flag)),flag=flagDefault;else flag=parameters.flag; end
  if (isfield(parameter,'fTrue') == 0 || isempty(parameters.fTrue)),fTrue=fTrueDefault;else fTrue=parameters.fTrue; end
  ...
end

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