Matlab에서 함수 매개 변수의 기본값을 어떻게 설정합니까?


127

Matlab에 기본 인수를 사용할 수 있습니까? 예를 들면 다음과 같습니다.

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

진정한 솔루션을 wave 함수에 대한 선택적 인수로 만들고 싶습니다. 가능하다면 누구나 올바른 방법을 보여줄 수 있습니까? 현재 위의 내용을 게시하려고하는데 다음과 같은 결과가 나타납니다.

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

답변:


151

시도한 것처럼 직접 수행 할 수있는 방법은 없습니다.

일반적인 방법은 "varargs"를 사용하고 인수 수를 확인하는 것입니다. 다음과 같은 것 :

function f(arg1, arg2, arg3)

  if nargin < 3
    arg3 =   'some default'
  end

end

isempty등으로 할 수있는 더 멋진 일이 있으며 이러한 종류의 묶음을 묶은 패키지에 대해 Matlab central을 살펴볼 수 있습니다.

당신은 한 번 봐있을 수 있습니다 varargin, nargchk이런 종류의 물건에 대한, 등 그들은있는 거 유용한 기능입니다. varargs를 사용하면 가변 수의 최종 인수를 남길 수 있지만 일부 / 모든 기본값의 문제를 해결할 수는 없습니다.


58

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정치인), 유지 관리가 쉽고 작고 유연합니다.
JnBrymn

19

약간 덜 해킹 된 또 다른 방법은

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

Coder가 "exist"기능을 지원하지 않기 때문에 MATLAB Coder를 사용하여 C 코드를 생성하려는 경우이 옵션이 작동하지 않습니다.
Dave Tillman

10

그렇습니다. 당신이 작성한대로 할 수있는 능력을 갖는 것이 정말 좋을 것입니다. 그러나 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의 핸들 그래픽 도구와 최적화, odeset 등에서 볼 수 있습니다.

이러한 속성 / 값 쌍으로 작업하기위한 수단으로, 함수에 완전 가변 개수의 인수를 입력하는 방법으로 varargin에 대해 배워야합니다. 나는 그러한 속성 / 값 쌍 parse_pv_pairs.m 과 함께 작동하는 유틸리티를 작성하고 게시 했습니다 . 속성 / 값 쌍을 MATLAB 구조로 변환하는 데 도움이됩니다. 또한 각 매개 변수에 기본값을 제공 할 수 있습니다. 다루기 어려운 매개 변수 목록을 구조로 변환하는 것은 MATLAB에서 매개 변수를 전달하는 아주 좋은 방법입니다.


7

이것은 "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에서 제거 될 수 있지만 사용할 수있는 'hack'도 있습니다. eval 함수는 실제로 첫 번째 오류가 발생하면 두 번째 인수가 실행되는 두 개의 인수를 허용합니다.

따라서 우리는 사용할 수 있습니다

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

인수의 기본값으로 값 1을 사용하려면


3

나는이 문제를 해결할 수있는 아주 좋은 방법을 찾았다. 다음은 내가 작성하는 기능에서 직접 해제되었으며 원하는대로 작동하는 것 같습니다.

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

내가 공유 할 줄 ​​알았는데


3

Matlab의 개발자 중 한 명인 Loren 이이 블로그 게시물 을 지적한 사람이 아무도 없습니다 . 접근 방식은 기반으로 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{:};

그래도 얻을 수 없다면 Loren의 전체 블로그 게시물을 읽으십시오. 위치 기본값 이 누락 된 후속 블로그 게시물 을 작성했습니다 . 나는 당신이 다음과 같은 것을 쓸 수 있음을 의미합니다.

somefun2Alt(a, b, '', 42)

아직도 기본이 eps에 대한 값 tol매개 변수를 (그리고 @magic위한 콜백func 물론). Loren의 코드는 약간 까다로운 수정으로 이것을 허용합니다.

마지막으로이 방법의 몇 가지 장점은 다음과 같습니다.

  1. 많은 기본값이 있어도 상용구 코드는 크지 않습니다 ( if-then-else각각의 새로운 기본값으로 길어지는 접근 방식 과 달리 )
  2. 모든 기본값은 한 곳에 있습니다. 그중 하나라도 변경해야 할 경우 볼 곳이 하나뿐입니다.

트로피도 역시 단점이 있습니다. Matlab 쉘에서 함수를 입력하고 해당 매개 변수를 잊어 버린 경우 도움이되지 않는 varargin힌트로 표시됩니다. 이를 처리하려면 의미있는 사용법 절을 작성하는 것이 좋습니다.


후속 블로그 게시물에 대한 링크가 손상되었습니다. 고칠 수 있습니까?
equaeghe

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

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

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"은 모든 후속 입력을 수집하는 셀형 배열이므로 셀형 배열 인덱싱을 사용하여 값을 제거해야합니다.
gnovice

비전을 확인해야합니다. 나는 어제 매뉴얼에서 그 어느 것도 보지 못했다고 맹세한다 :(
kyle

@kyle : 걱정하지 마세요. 우리 모두 실수를합니다. 그렇기 때문에 SO의 위키 스타일을 좋아하는 이유가 있습니다. =)
gnovice

1

Matlab은이를위한 메커니즘을 제공하지 않지만 inputParser 또는 "if nargin <1 ..."시퀀스보다 더 터프한 Userland 코드를 생성 할 수 있습니다.

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 함수에서 작동하지 않습니다. 그러나 매우 편리합니다.


0

parseparamsmatlab 에서 명령 을 사용할 수 있습니다 . 사용법은 다음과 같습니다.

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;

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

옥타브를 사용하면 다음과 같이 할 수 있지만 슬프게도 matlab 은이 가능성을 지원하지 않습니다.

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

( 문서 에서 가져온 )


0

나는 좀 더 객체 지향적 인 방식으로 이것을하고 싶다. wave ()를 호출하기 전에 예를 들어 구조체 안에 인수를 저장하십시오. 하나의 매개 변수 :

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

그런 다음 wave 함수 내에서 struct 매개 변수에 'flag'라는 필드가 포함되어 있는지 여부와 해당 값이 비어 있지 않은지 확인하십시오. 그런 다음 이전에 정의한 기본값 또는 parameters struct에서 인수로 제공된 값을 여덟 가지로 지정하십시오.

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

이것은 주어진 인수의 순서에 의존하지 않기 때문에 많은 수의 인수를 처리하기가 더 쉽습니다. 즉, 함수 서명을 변경할 필요가 없으므로 나중에 인수를 더 추가해야 할 경우에도 유용합니다.


MATLAB 표준 이름-값 쌍을 따르지 않겠습니까? wave(a,b,'flag',42,'fTrue',1)
Cris Luengo

특히 매개 변수가 적은 경우 특히 옵션입니다. 그러나 많은 수의 이름-값 쌍으로 wave ()를 호출하면 코드의 가독성이 떨어질 수 있습니다. 따라서 종종 특정 입력을 구조체로 그룹화하는 것을 선호합니다.
CheshireCat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.