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

110

Возможно ли иметь аргументы по умолчанию в 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.

Спасибо!

Теги:
arguments
default

15 ответов

142
Лучший ответ

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

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

function f(arg1,arg2,arg3)

  if nargin < 3
    arg3 =   'some default'
  end

end

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

[обновление] рад, что помог.

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

53

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

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

После того, как вы определите функцию wave следующим образом:

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, поэтому оставил пустое значение проверки.

  • 7
    Как я могу сказать, это предпочтительный метод. Он чистый, самодокументируемый (тем более кучка if nargin государственных if nargin ), простой в обслуживании, компактный и гибкий.
18

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

function output = fun(input)
   if ~exist('input','var'), input='BlahBlahBlah'; end
   ...
end
  • 0
    Эта опция не работает, если вы собираетесь использовать MATLAB Coder для генерации кода на C, так как Coder не поддерживает функцию «exist».
9

Да, может быть очень приятно иметь возможность делать то, что вы написали. Но это невозможно в 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

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

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

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

3

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

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

Привет!

3

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

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

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

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

3

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

2

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

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 для параметра tol@magic обратного вызова для func, конечно). Код Loren позволяет это с небольшой, но сложной модификацией.

Наконец, лишь несколько преимуществ этого подхода:

  • Даже с большим количеством значений по умолчанию код шаблона не становится огромным (в отличие от семейства подходов if-then-else, которые становятся длиннее с каждым новым значением по умолчанию)
  • Все значения по умолчанию находятся в одном месте. Если кто-то из них нуждается в изменении, у вас есть только одно место, чтобы посмотреть.

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

  • 0
    Ссылка на ваш пост в блоге не работает; ты можешь починить это?
2

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

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

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

2

После осознания ASSIGNIN (спасибо этот ответ b3) и EVALIN Я написал две функции, чтобы, наконец, получить очень простая структура вызова:

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 workspace
% and if it is not empty

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

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

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 help - подсказки автозаполнения в командной строке - не работают для функций varargin. Но это довольно удобно.

1

Это более или менее снято с руководство 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
  • 1
    В коде было несколько ошибок, которые я исправил. Во-первых, необходимо определить «optargin». Во-вторых, «varargin» - это массив ячеек, который собирает все последующие входные данные, поэтому вы должны использовать индексирование ячеек для удаления значений из него.
  • 0
    Мне нужно проверить свое зрение; Клянусь, я не видел ничего из этого в руководстве вчера :(
Показать ещё 1 комментарий
0

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

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

(взято из doc)

0
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.

0

вы можете использовать команду parseparams в 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;

Ещё вопросы

Сообщество Overcoder
Наверх
Меню