2009-04-09 2 views
12

Bei einer Funktion wie:nargin vs exist

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

ich gesehen habe Leute benutzen so etwas wie die folgende an der Stelle der nargin Version

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

Ich frage mich, ob es irgendeine Präferenz in beide Richtungen?

Die "~ exist ..." -Version hat für mich den Vorteil, dass wenn ich die Reihenfolge meiner Funktionsparameter ändere, diese immer noch funktionieren sollte. Meine Sorge bei diesem Ansatz ist jedoch, dass ich versehentlich Variablen übernehmen könnte, die global oder im Rahmen einer umgebenden Funktion bei verschachtelten Funktionen definiert sind.

Haben Sie irgendwelche Gedanken zu diesem Thema?

Antwort

10

Beide sollten funktionieren. Aber ...

Exist neigt dazu, langsam zu sein, da es für die Variable in Ihrem Arbeitsbereich durchsehen muss. Wenn Sie Fehlerprüfungen wie diese schreiben, wollen Sie nicht, dass sie CPU-Zyklen aufsaugen. Der Test gegen Nargin ist ein einfacher Test gegen einen einzelnen numerischen Wert.

Ich würde im Allgemeinen auch einen umfangreicheren Test vorschlagen. So etwas wie

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

    myparam = defaultvalue; 

elseif 

    ... 

end 

Innerhalb des elseif Zweig, werde ich eine Reihe von zusätzlichen Tests unterzogen, um zu sehen, wenn der Parameter die erwartete Größe, Form, Klasse von Variablen usw. Wenn diese Tests fehlschlagen, werde ich zurückkehren eine freundliche Fehlermeldung, die erklärt, was falsch war.

7

ich mit nargin aus zwei Gründen gehen würde:

  1. Wenn Sie die Reihenfolge der Parameter an die Funktion ändern, die Eingabe bis zur Festsetzung Prüfcodes die am wenigsten Ihrer Probleme sein wird; Sie müssen auch alle Call-Sites auf Ihre Funktion aktualisieren.

  2. Nargin ist viel billiger. existieren, selbst wenn man nur nach Variablen sucht, muss man den gesamten Arbeitsbereich scannen und dabei eine Reihe von String-Vergleichen durchführen. Die Nargin-Methode besteht nur aus einem Skalar weniger als Operation.

4

Ich validiere immer Argumente mit nargchk, und dann gehen Sie mit den nargin Tests wie Sie sie hatten. Andere wiesen darauf hin, dass sie billiger sind, und ich denke klarer.

In Funktionen, die ich voraussichtlich wiederverwenden werde, stelle ich immer eine Menge von Prüfungen in den Vordergrund und strukturiere dann den Code, um später die eigentliche Implementierung aufzurufen.

Ich neige dazu, auch optionale Argumente zu strukturieren (wenn nicht varargin verwendet wird) wie folgt aus:

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

, wie ich denke, das macht es noch deutlicher, wenn man die Datei, die Argumente zu erwarten sind optional zu sein.

4

Ich würde mit der NARGIN Option gehen, aus den Gründen, die von SCFrench aufgeführt sind.Ein weiterer Vorteil: Ich finde mich oft in Verbindung mit einer SWITCH Anweisung, wenn ich mehr als 2 Eingabeargumente haben:

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

Dies scheint praktisch, aber ich frage mich, ob das mit einer Leistung kommt Elfmeter... – embert

3

Für diejenigen MATLAB R2007b oder höher verwenden,
hier ist eine bessere Antwort: InputParser

Es spart die Mühe, jedes Hinzufügen, Entfernen, Umbenennen und Neuanordnen von Argumenten zu synchronisieren.

(Wie viel Sie auf Ihrem Programmierstil abhängen retten würde, aber es ist nicht eine nette Art und Weise als InputParser.)

ich es für die Geschwindigkeit nicht getestet haben, aber wenn Sie dauert funktionieren mehr als 1000 Millisekunden run, es gibt keinen Grund, von der Geschwindigkeit von InputParser betroffen zu sein.

Beispiel:

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

ich stark aus zwei Gründen exist über die nargin Option bevorzugen.

1. Nach viel Code von Menschen zu lesen, die noch auf ihren eigenen Code zurückblicken nie gelehrt wurden fühlte, ich nur für diese stärker, als exist der Code lesbar macht. Zum Beispiel habe ich einmal eine Funktion wie diese gefunden. Für Ihre Bequemlichkeit habe ich die Variablen sinnvolle Namen:

[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 
% ... 

Dies ist dann von if nargin < n für jede Variable anders als die ersten beiden folgte. Der einzige Grund, warum ich folgen konnte, was die nargin(n) sein sollte, ohne die Kopfzeile zu zählen, ist, dass die if nargin < n immer gefolgt wurde (nur manchmal ein paar Zeilen Code und) die Deklaration der fehlenden Eingabe mit dem Standardwert. Für größere Chucks Code in der if nargin < n würde ich definitiv den Überblick verlieren.

2.exist prüft nicht wirklich den kompletten Arbeitsbereich wenn von einer Funktion genannt. Sicher, der Vergleich zweier Zahlen ist weniger kostenintensiv als der Vergleich einiger Strings, aber wenn er am Anfang einer Funktion verwendet wird, um Standardwerte für die nicht gegebenen Parameter aufzufüllen, ist es in Ordnung. Betrachten Sie die folgende Funktion:

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 

Und dann die Ausführung der folgenden Schritte aus:

A = magic(3); 
B = magic(4); 
testExist(A) 

Ergebnisse in dieser Ausgabe:

'exist' in a function ignores the variables in the workspace, but checks the function space. 
Verwandte Themen