Ist es möglich, Standardargumente in Matlab zu haben? Zum Beispiel hier:
function wave(a, b, n, k, T, f, flag, fTrue=inline('0'))
Ich möchte, dass die wahre Lösung ein optionales Argument für die Wellenfunktion ist. Kann es jemand nachweisen, wie dies möglich ist? Momentan versuche ich das, was ich oben gepostet habe und bekomme:
??? 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.
Es gibt keine direkte Möglichkeit, dies so zu tun, wie Sie es versucht haben.
Der übliche Ansatz besteht darin, "varargs" zu verwenden und die Anzahl der Argumente zu überprüfen. So etwas wie:
function f(arg1, arg2, arg3)
if nargin < 3
arg3 = 'some default'
end
end
Es gibt ein paar schickere Dinge, die Sie mit isempty
usw. machen können, und Sie möchten Matlab Central nach Paketen durchsuchen, die diese Art von Dingen enthalten.
Sie können sich varargin
, nargchk
usw. ansehen. Sie sind nützliche Funktionen für diese Art von Dingen. Mit varargs können Sie eine variable Anzahl von abschließenden Argumenten belassen, was jedoch das Problem der Standardwerte für einige/alle nicht löst.
Ich habe das Objekt inputParser
verwendet, um die Standardeinstellungen festzulegen. Matlab akzeptiert nicht das Python-ähnliche Format, das Sie in der Frage angegeben haben, aber Sie sollten die Funktion folgendermaßen aufrufen können:
wave(a,b,n,k,T,f,flag,'fTrue',inline('0'))
Nachdem Sie die wave
-Funktion folgendermaßen definiert haben:
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{:});
Nun sind die in die Funktion übergebenen Werte über i_p.Results
verfügbar. Ich war mir auch nicht sicher, wie ich prüfen sollte, ob der Parameter, der für ftrue
übergeben wurde, tatsächlich eine inline
-Funktion war.
Eine andere, etwas weniger gehackte Art ist
function output = fun(input)
if ~exist('input','var'), input='BlahBlahBlah'; end
...
end
Ja, es wäre wirklich schön, wenn Sie die Möglichkeit haben, das zu tun, was Sie geschrieben haben. In MATLAB ist dies jedoch nicht möglich. Viele meiner Dienstprogramme, die Standardwerte für die Argumente zulassen, werden in der Regel mit expliziten Überprüfungen am Anfang geschrieben:
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, also würde ich generell eine bessere, aussagekräftigere Fehlermeldung anwenden. Beachten Sie, dass die Überprüfung auf eine leere Variable dem Benutzer ermöglicht, ein leeres Paar [] als Platzhalter für eine Variable zu übergeben, die ihren Standardwert annimmt. Der Autor muss jedoch weiterhin den Code angeben, um dieses leere Argument durch seinen Standardwert zu ersetzen.
Meine Hilfsprogramme mit MANY-Parametern, die alle über Standardargumente verfügen, verwenden häufig eine Eigenschafts-/Wert-Paar-Schnittstelle für Standardargumente. Dieses grundlegende Paradigma zeigt sich in den Griff-Grafiktools in matlab sowie in optimset, odeset usw.
Um mit diesen Eigenschafts-/Wert-Paaren arbeiten zu können, müssen Sie sich mit Varargin vertraut machen, um eine vollständig variable Anzahl von Argumenten in eine Funktion einzugeben. Ich habe ein Hilfsprogramm geschrieben (und gepostet), um mit solchen Eigenschafts-/Wert-Paaren zu arbeiten, parse_pv_pairs.m . Es hilft Ihnen, Eigenschafts-/Wertepaare in eine Matlab-Struktur umzuwandeln. Sie können auch Standardwerte für jeden Parameter angeben. Das Umwandeln einer schwerfälligen Liste von Parametern in eine Struktur ist eine sehr schöne Möglichkeit, sie in MATLAB herumzugeben.
Dies ist meine einfache Möglichkeit, mit "try" Standardwerte für eine Funktion festzulegen:
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
Grüße!
Ich habe festgestellt, dass die Funktion parseArgs sehr hilfreich sein kann.
Es gibt auch einen "Hack", der verwendet werden kann, obwohl er zu einem bestimmten Zeitpunkt aus matlab entfernt werden kann: Function eval akzeptiert tatsächlich zwei Argumente, von denen das zweite ausgeführt wird, wenn beim ersten ein Fehler aufgetreten ist.
So können wir verwenden
function output = fun(input)
eval('input;', 'input = 1;');
...
end
wert 1 als Standard für das Argument verwenden
Ich bin verwirrt, dass niemand darauf hingewiesen hat dieser Blog-Beitrag von Loren, einem der Matlab-Entwickler. Der Ansatz basiert auf varargin
und vermeidet all diese endlosen und schmerzhaften if-then-else
oder switch
Fälle mit verschachtelten Bedingungen. Bei wenigen Standardwerten ist der Effekt dramatisch . Hier ist ein Beispiel aus dem verlinkten Blog:
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{:};
Wenn Sie es immer noch nicht verstehen, lesen Sie den gesamten Blog-Beitrag von Loren. Ich habe ein Follow-up geschrieben Blogpost , das sich mit fehlenden Positions-Standardwerten befasst. Ich meine, du könntest so etwas schreiben wie:
somefun2Alt(a, b, '', 42)
und haben immer noch den Standardwert eps
für den Parameter tol
(und @magic
Rückruf für func
natürlich). Lorens Code erlaubt dies mit einer kleinen, aber kniffligen Modifikation.
Abschließend noch einige Vorteile dieses Ansatzes:
if-then-else
Ansätze, die mit jedem neuen Standardwert länger werden)Trotzdem gibt es auch einen Nachteil. Wenn Sie die Funktion in Matlab Shell eingeben und ihre Parameter vergessen, wird ein nicht nützlicher varargin
als Hinweis angezeigt. Um damit umzugehen, wird empfohlen, eine sinnvolle Verwendungsklausel zu schreiben.
Ich glaube, ich habe einen ziemlich raffinierten Weg gefunden, um mit diesem Problem umzugehen, da ich nur drei Codezeilen benötigte (Zeilenumbrüche sperren). Folgendes wird direkt von einer Funktion, die ich schreibe, abgehoben und scheint wie gewünscht zu funktionieren:
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
Ich dachte nur, ich würde es teilen.
Nachdem ich ASSIGNIN (dank dieser Antwort by b3 ) und EVALIN gewusst habe, habe ich zwei Funktionen geschrieben, um endlich eine sehr einfache Aufrufstruktur zu erhalten:
setParameterDefault('fTrue', inline('0'));
Hier ist die Auflistung:
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
und
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 ')']) ;
Dies ist mehr oder weniger aus dem Matlab Manual ; Ich habe nur vorübergehende Erfahrung ...
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 bietet hierfür keinen Mechanismus, aber Sie können einen in Userland-Code konstruieren, der eher als inputParser- oder "if nargin <1 ..." - Sequenzen ist.
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
Dann können Sie es in Ihren Funktionen so aufrufen:
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'});
Die Formatierung ist eine Konvention, mit der Sie von Parameternamen bis zu ihren Standardwerten herunterlesen können. Sie können Ihr getargs () mit optionalen Parametertypspezifikationen (zur Fehlererkennung oder impliziten Konvertierung) und Argumentzählbereichen erweitern.
Dieser Ansatz hat zwei Nachteile. Erstens ist es langsam, deshalb möchten Sie es nicht für Funktionen verwenden, die in Schleifen aufgerufen werden. Zweitens funktioniert die Funktionshilfe von Matlab - die Hinweise zur automatischen Vervollständigung in der Befehlszeile - nicht für Varargin-Funktionen. Aber es ist ziemlich bequem.
möglicherweise möchten Sie den Befehl parseparams
in matlab verwenden. Die Verwendung würde wie folgt aussehen:
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;
z.B. f(2,4,'c',3)
bewirkt, dass der Parameter c
3 ist.
wenn Sie Octave verwenden würden, könnten Sie dies so tun - aber leider unterstützt matlab diese Möglichkeit nicht
function hello (who = "World")
printf ("Hello, %s!\n", who);
endfunction
(aus dem doc genommen)
Ich mache das gerne etwas objektorientierter. Bevor Sie wave () aufrufen, speichern Sie einige Ihrer Argumente in einem struct, z. Parameter genannt:
parameters.flag =42;
parameters.fTrue =1;
wave(a,b,n,k,T,f,parameters);
Prüfen Sie dann in der Wave-Funktion, ob die Strukturparameter ein Feld namens 'Flag' enthalten und wenn ja, ob der Wert nicht leer ist. Weisen Sie ihm dann einen zuvor definierten Standardwert oder den als Argument angegebenen Wert in den Parametern struct zu:
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
Dies erleichtert die Handhabung einer großen Anzahl von Argumenten, da sie nicht von der Reihenfolge der angegebenen Argumente abhängt. Dies ist jedoch auch hilfreich, wenn Sie später weitere Argumente hinzufügen müssen, da Sie dazu nicht die Signatur der Funktionen ändern müssen.