wake-up-neo.com

Umgang mit Name/Wert-Paaren von Funktionsargumenten in MATLAB

Ich habe eine Funktion, die optionale Argumente als Name/Wert-Paare akzeptiert.

function example(varargin)
% Lots of set up stuff
vargs = varargin;
nargs = length(vargs);
names = vargs(1:2:nargs);
values = vargs(2:2:nargs);

validnames = {'foo', 'bar', 'baz'};    
for name = names
   validatestring(name{:}, validnames);
end

% Do something ...
foo = strmatch('foo', names);
disp(values(foo))
end

example('foo', 1:10, 'bar', 'qwerty')

Es scheint, dass es sehr aufwendig ist, die entsprechenden Werte zu extrahieren (und es ist immer noch nicht besonders robust, wenn die Eingaben falsch sind). Gibt es eine bessere Möglichkeit, mit diesen Name/Wert-Paaren umzugehen? Gibt es Hilfsfunktionen, die mit MATLAB zur Unterstützung geliefert werden?

61
Richie Cotton

Ich bevorzuge Strukturen für meine Optionen. Auf diese Weise können Sie die Optionen auf einfache Weise speichern und definieren. Das Ganze wird auch ziemlich kompakt.

function example(varargin)

%# define defaults at the beginning of the code so that you do not need to
%# scroll way down in case you want to change something or if the help is
%# incomplete
options = struct('firstparameter',1,'secondparameter',magic(3));

%# read the acceptable names
optionNames = fieldnames(options);

%# count arguments
nArgs = length(varargin);
if round(nArgs/2)~=nArgs/2
   error('EXAMPLE needs propertyName/propertyValue pairs')
end

for pair = reshape(varargin,2,[]) %# pair is {propName;propValue}
   inpName = lower(pair{1}); %# make case insensitive

   if any(strcmp(inpName,optionNames))
      %# overwrite options. If you want you can test for the right class here
      %# Also, if you find out that there is an option you keep getting wrong,
      %# you can use "if strcmp(inpName,'problemOption'),testMore,end"-statements
      options.(inpName) = pair{2};
   else
      error('%s is not a recognized parameter name',inpName)
   end
end
55
Jonas

InputParser hilft dabei. Weitere Informationen finden Sie unter Parse-Funktionseingaben .

43

Ich könnte stundenlang darüber reden, habe aber immer noch keine gute Sicht auf die allgemeine Signaturverarbeitung von Matlab. Aber hier sind ein paar Ratschläge.

Nehmen Sie zunächst einen Laissez-Faire-Ansatz zur Überprüfung der Eingabetypen. Vertrauen Sie dem Anrufer. Wenn Sie wirklich starke Typenprüfung wünschen, möchten Sie eine statische Sprache wie Java. Versuchen Sie, die Typensicherheit überall in Matlab durchzusetzen, und Sie erhalten am Ende einen Großteil Ihres LOC und der Ausführungszeit, die für Laufzeit-Typprüfungen und Zwang im Benutzerland aufgewendet werden, was einen Großteil der Leistungsfähigkeit und Entwicklungsgeschwindigkeit von Matlab einbringt . Ich habe es auf die harte Tour gelernt.

Für API-Signaturen (Funktionen, die von anderen Funktionen statt von den Befehlszeilen aufgerufen werden sollen) sollten Sie die Verwendung eines einzelnen Args-Arguments anstelle von varargin in Betracht ziehen. Dann kann es zwischen mehreren Argumenten weitergegeben werden, ohne dass es in eine durch Kommas getrennte Liste für Varargin-Signaturen konvertiert werden muss. Strukturen, wie Jonas sagt, sind sehr bequem. Es gibt auch einen Nice-Isomorphismus zwischen structs und n-by-2 {name, value; ...} -Zellen, und Sie können ein paar Funktionen einrichten, um diese innerhalb Ihrer Funktionen in die zu konvertieren, die sie intern verwenden möchten.

function example(args)
%EXAMPLE
%
% Where args is a struct or {name,val;...} cell array

Unabhängig davon, ob Sie inputParser verwenden oder einen eigenen Name/Val-Parser wie diese anderen feinen Beispiele rollen, verpacken Sie ihn in einer separaten Standardfunktion, die Sie oben in Ihren Funktionen aufrufen, die über Namens-/Val-Signaturen verfügen. Lassen Sie die Standardwertliste in einer Datenstruktur akzeptieren, die sich bequem ausschreiben lässt. Ihre arg-syntaktischen Aufrufe ähneln Funktionsdeklarationsdeklarationen, die die Lesbarkeit verbessern und den Code für das Kopieren und Einfügen von Textbausteinen vermeiden.

So könnten die Parsing-Anrufe aussehen.

function out = my_example_function(varargin)
%MY_EXAMPLE_FUNCTION Example function 

% No type handling
args = parsemyargs(varargin, {
    'Stations'  {'ORD','SFO','LGA'}
    'Reading'   'Min Temp'
    'FromDate'  '1/1/2000'
    'ToDate'    today
    'Units'     'deg. C'
    });
fprintf('\nArgs:\n');
disp(args);

% With type handling
typed_args = parsemyargs(varargin, {
    'Stations'  {'ORD','SFO','LGA'}     'cellstr'
    'Reading'   'Min Temp'              []
    'FromDate'  '1/1/2000'              'datenum'
    'ToDate'    today                   'datenum'
    'Units'     'deg. C'                []
    });
fprintf('\nWith type handling:\n');
disp(typed_args);

% And now in your function body, you just reference stuff like
% args.Stations
% args.FromDate

Und hier ist eine Funktion, um das Parsen von Namen und Werten auf diese Weise zu implementieren. Sie könnten es aushöhlen und durch inputParser, Ihre eigenen Typkonventionen usw. ersetzen. Ich denke, die n-by-2-Zellenkonvention macht gut lesbaren Quellcode; überlege, das zu behalten. Strukturen sind normalerweise im empfangenden Code bequemer zu handhaben, die n-by-2-Zellen sind jedoch einfacher zu konstruieren, indem Ausdrücke und Literale verwendet werden. (Strukturen erfordern die Fortsetzung ", ..." in jeder Zeile und schützen die Zellwerte vor der Erweiterung auf nichtskalare Strukturen.)

function out = parsemyargs(args, defaults)
%PARSEMYARGS Arg parser helper
%
% out = parsemyargs(Args, Defaults)
%
% Parses name/value argument pairs.
%
% Args is what you pass your varargin in to. It may be
%
% ArgTypes is a list of argument names, default values, and optionally
% argument types for the inputs. It is an n-by-1, n-by-2 or n-by-3 cell in one
% of these forms forms:
%   { Name; ... }
%   { Name, DefaultValue; ... }
%   { Name, DefaultValue, Type; ... }
% You may also pass a struct, which is converted to the first form, or a
% cell row vector containing name/value pairs as 
%   { Name,DefaultValue, Name,DefaultValue,... }
% Row vectors are only supported because it's unambiguous when the 2-d form
% has at most 3 columns. If there were more columns possible, I think you'd
% have to require the 2-d form because 4-element long vectors would be
% ambiguous as to whether they were on record, or two records with two
% columns omitted.
%
% Returns struct.
%
% This is slow - don't use name/value signatures functions that will called
% in tight loops.

args = structify(args);
defaults = parse_defaults(defaults);

% You could normalize case if you want to. I recommend you don't; it's a runtime cost
% and just one more potential source of inconsistency.
%[args,defaults] = normalize_case_somehow(args, defaults);

out = merge_args(args, defaults);

%%
function out = parse_defaults(x)
%PARSE_DEFAULTS Parse the default arg spec structure
%
% Returns n-by-3 cellrec in form {Name,DefaultValue,Type;...}.

if isstruct(x)
    if ~isscalar(x)
        error('struct defaults must be scalar');
    end
    x = [fieldnames(s) struct2cell(s)];
end
if ~iscell(x)
    error('invalid defaults');
end

% Allow {name,val, name,val,...} row vectors
% Does not work for the general case of >3 columns in the 2-d form!
if size(x,1) == 1 && size(x,2) > 3
    x = reshape(x, [numel(x)/2 2]);
end

% Fill in omitted columns
if size(x,2) < 2
    x(:,2) = {[]}; % Make everything default to value []
end
if size(x,2) < 3
    x(:,3) = {[]}; % No default type conversion
end

out = x;

%%
function out = structify(x)
%STRUCTIFY Convert a struct or name/value list or record list to struct

if isempty(x)
    out = struct;
elseif iscell(x)
    % Cells can be {name,val;...} or {name,val,...}
    if (size(x,1) == 1) && size(x,2) > 2
        % Reshape {name,val, name,val, ... } list to {name,val; ... }
        x = reshape(x, [2 numel(x)/2]);
    end
    if size(x,2) ~= 2
        error('Invalid args: cells must be n-by-2 {name,val;...} or vector {name,val,...} list');
    end

    % Convert {name,val, name,val, ...} list to struct
    if ~iscellstr(x(:,1))
        error('Invalid names in name/val argument list');
    end
    % Little trick for building structs from name/vals
    % This protects cellstr arguments from expanding into nonscalar structs
    x(:,2) = num2cell(x(:,2)); 
    x = x';
    x = x(:);
    out = struct(x{:});
elseif isstruct(x)
    if ~isscalar(x)
        error('struct args must be scalar');
    end
    out = x;
end

%%
function out = merge_args(args, defaults)

out = structify(defaults(:,[1 2]));
% Apply user arguments
% You could normalize case if you wanted, but I avoid it because it's a
% runtime cost and one more chance for inconsistency.
names = fieldnames(args);
for i = 1:numel(names)
    out.(names{i}) = args.(names{i});
end
% Check and convert types
for i = 1:size(defaults,1)
    [name,defaultVal,type] = defaults{i,:};
    if ~isempty(type)
        out.(name) = needa(type, out.(name), type);
    end
end

%%
function out = needa(type, value, name)
%NEEDA Check that a value is of a given type, and convert if needed
%
% out = needa(type, value)

% HACK to support common 'pseudotypes' that aren't real Matlab types
switch type
    case 'cellstr'
        isThatType = iscellstr(value);
    case 'datenum'
        isThatType = isnumeric(value);
    otherwise
        isThatType = isa(value, type);
end

if isThatType
    out = value;
else
    % Here you can auto-convert if you're feeling brave. Assumes that the
    % conversion constructor form of all type names works.
    % Unfortunately this ends up with bad results if you try converting
    % between string and number (you get Unicode encoding/decoding). Use
    % at your discretion.
    % If you don't want to try autoconverting, just throw an error instead,
    % with:
    % error('Argument %s must be a %s; got a %s', name, type, class(value));
    try
        out = feval(type, value);
    catch err
        error('Failed converting argument %s from %s to %s: %s',...
            name, class(value), type, err.message);
    end
end

Es ist so bedauerlich, dass Strings und Datenums in Matlab keine erstklassigen Typen sind.

11
Andrew Janke

Ich persönlich verwende eine benutzerdefinierte Funktion, die von einer privaten Methode abgeleitet ist, die von vielen Statistics Toolbox-Funktionen verwendet wird (wie kmeans, pca, svmtrain, ttest2, ...).

Da es sich um eine interne Dienstprogrammfunktion handelt, wurde es geändert und in den Releases mehrmals umbenannt. Suchen Sie je nach MATLAB-Version nach einer der folgenden Dateien:

%# old versions
which -all statgetargs
which -all internal.stats.getargs
which -all internal.stats.parseArgs

%# current one, as of R2014a
which -all statslib.internal.parseArgs

Wie bei jeder nicht dokumentierten Funktion gibt es keine Garantien und sie könnte in späteren Releases ohne vorherige Ankündigung aus MATLAB entfernt werden ... Jedenfalls glaube ich, dass jemand eine alte Version als getargs auf dem Dateiaustausch veröffentlicht hat.

Die Funktion verarbeitet Parameter als Name/Wert-Paare und verwendet einen Satz gültiger Parameternamen zusammen mit ihren Standardwerten. Die analysierten Parameter werden als separate Ausgangsvariablen zurückgegeben. Standardmäßig lösen nicht erkannte Name/Wert-Paare einen Fehler aus, wir können sie jedoch auch in einer zusätzlichen Ausgabe im Hintergrund erfassen. Hier ist die Funktionsbeschreibung:

$MATLABROOT\toolbox\stats\stats\+internal\+stats\parseArgs.m

function varargout = parseArgs(pnames, dflts, varargin)
%
% [A,B,...] = parseArgs(PNAMES, DFLTS, 'NAME1',VAL1, 'NAME2',VAL2, ...)
%   PNAMES   : cell array of N valid parameter names.
%   DFLTS    : cell array of N default values for these parameters.
%   varargin : Remaining arguments as name/value pairs to be parsed.
%   [A,B,...]: N outputs assigned in the same order as the names in PNAMES.
%
% [A,B,...,SETFLAG] = parseArgs(...)
%   SETFLAG  : structure of N fields for each parameter, indicates whether
%              the value was parsed from input, or taken from the defaults.
%
% [A,B,...,SETFLAG,EXTRA] = parseArgs(...)
%   EXTRA    : cell array containing name/value parameters pairs not
%              specified in PNAMES.

Beispiel:

function my_plot(x, varargin)
    %# valid parameters, and their default values
    pnames = {'Color', 'LineWidth', 'LineStyle', 'Title'};
    dflts  = {    'r',           2,        '--',      []};

    %# parse function arguments
    [clr,lw,ls,txt] = internal.stats.parseArgs(pnames, dflts, varargin{:});

    %# use the processed values: clr, lw, ls, txt
    %# corresponding to the specified parameters
    %# ...
end

Diese Beispielfunktion kann nun auf eine der folgenden Arten aufgerufen werden:

>> my_plot(data)                                %# use the defaults
>> my_plot(data, 'linestyle','-', 'Color','b')  %# any order, case insensitive
>> my_plot(data, 'Col',[0.5 0.5 0.5])           %# partial name match

Hier sind einige ungültige Aufrufe und die aufgetretenen Fehler:

%# unrecognized parameter
>> my_plot(x, 'width',0)
Error using [...]
Invalid parameter name: width.

%# bad parameter
>> my_plot(x, 1,2)
Error using [...]
Parameter name must be text.

%# wrong number of arguments
>> my_plot(x, 'invalid')
Error using [...]
Wrong number of arguments.

%# ambiguous partial match
>> my_plot(x, 'line','-')
Error using [...]
Ambiguous parameter name: line.

inputParser:

Wie bereits erwähnt, ist der offiziell empfohlene Ansatz für die Syntaxanalyse von Funktionen die Verwendung von inputParser class. Es unterstützt verschiedene Schemata, z. B. die Angabe erforderlicher Eingaben, optionale Positionsargumente und Name/Wert-Parameter. Es ermöglicht auch die Durchführung von validation an den Eingaben (z. B. Überprüfung der Klasse/des Typs und der Größe/Form der Argumente).

6
Amro

Lesen Sie Lorens informativer Beitrag zu diesem Thema. Vergessen Sie nicht, die Kommentare zu lesen ... - Sie werden feststellen, dass es zu diesem Thema einige unterschiedliche Ansätze gibt. Alle arbeiten, daher ist die Auswahl einer bevorzugten Methode eine Frage des persönlichen Geschmacks und der Wartbarkeit.

5
Yair Altman

Ich bin ein größerer Fan von selbstgepresstem Kesselplattencode wie folgt:

function TestExample(req1, req2, varargin)
for i = 1:2:length(varargin)
    if strcmpi(varargin{i}, 'alphabet')
        ALPHA = varargin{i+1};

    elseif strcmpi(varargin{i}, 'cutoff')
        CUTOFF = varargin{i+1};
        %we need to remove these so seqlogo doesn't get confused
        rm_inds = [rm_inds i, i+1]; %#ok<*AGROW>

    elseif strcmpi(varargin{i}, 'colors')
        colors = varargin{i+1};
        rm_inds = [rm_inds i, i+1]; 
    elseif strcmpi(varargin{i}, 'axes_handle')
        handle = varargin{i+1};
        rm_inds = [rm_inds i, i+1]; 
    elseif strcmpi(varargin{i}, 'top-n')
        TOPN = varargin{i+1};
        rm_inds = [rm_inds i, i+1];
    elseif strcmpi(varargin{i}, 'inds')
        npos = varargin{i+1};
        rm_inds = [rm_inds i, i+1];
    elseif strcmpi(varargin{i}, 'letterfile')
        LETTERFILE = varargin{i+1};
        rm_inds = [rm_inds i, i+1];
    elseif strcmpi(varargin{i}, 'letterstruct')
        lo = varargin{i+1};
        rm_inds = [rm_inds i, i+1];
    end
end

Auf diese Weise kann ich das "Option" simulieren, ein Wertepaar, das fast identisch ist mit dem, wie die meisten Matlab-Funktionen ihre Argumente annehmen.

Hoffentlich hilft das,

Wille

3
JudoWill

Hier ist die Lösung, die ich teste, basierend auf Jonas Idee.

function argStruct = NameValuePairToStruct(defaults, varargin)
%NAMEVALUEPAIRTOSTRUCT Converts name/value pairs to a struct.
% 
% ARGSTRUCT = NAMEVALUEPAIRTOSTRUCT(DEFAULTS, VARARGIN) converts
% name/value pairs to a struct, with defaults.  The function expects an
% even number of arguments to VARARGIN, alternating NAME then VALUE.
% (Each NAME should be a valid variable name.)
% 
% Examples: 
% 
% No defaults
% NameValuePairToStruct(struct, ...
%    'foo', 123, ...
%    'bar', 'qwerty', ...
%    'baz', magic(3))
% 
% With defaults
% NameValuePairToStruct( ...
%    struct('bar', 'dvorak', 'quux', eye(3)), ...
%    'foo', 123, ...
%    'bar', 'qwerty', ...
%    'baz', magic(3))
% 
% See also: inputParser

nArgs = length(varargin);
if rem(nArgs, 2) ~= 0
   error('NameValuePairToStruct:NotNameValuePairs', ...
      'Inputs were not name/value pairs');
end

argStruct = defaults;
for i = 1:2:nArgs
   name = varargin{i};
   if ~isvarname(name)
      error('NameValuePairToStruct:InvalidName', ...
         'A variable name was not valid');
   end
   argStruct = setfield(argStruct, name, varargin{i + 1});  %#ok<SFLD>
end

end
1
Richie Cotton

Es gibt eine raffinierte Funktion namens parsepvpairs, die sich gut darum kümmert, vorausgesetzt, Sie haben Zugriff auf die MATLAB-Finanz-Toolbox. Es benötigt drei Argumente, erwartete Feldnamen, Standardfeldwerte und die tatsächlich empfangenen Argumente.

Zum Beispiel eine Funktion, die eine HTML-Abbildung in MATLAB erstellt und die optionalen Feldwertpaare mit den Namen 'url', 'html' und 'title' annehmen kann. 

function htmldlg(varargin)
    names = {'url','html','title'};
    defaults = {[],[],'Padaco Help'};
    [url, html,titleStr] = parsepvpairs(names,defaults,varargin{:});

    %... code to create figure using the parsed input values
end
1
informaton

Seit Ewigkeiten benutze ich process_options.m . Es ist stabil, einfach zu bedienen und wurde in verschiedene Matlab-Frameworks integriert. Ich weiß jedoch nichts über die Leistung. Möglicherweise gibt es schnellere Implementierungen. 

Das Feature, das mir bei process_options am besten gefällt, ist der unused_args-Rückgabewert, der verwendet werden kann, um Eingabearrgs in Gruppen von Args für z.

Und Sie können einfach Standardwerte definieren.

Am wichtigsten: Die Verwendung von process_options.m führt normalerweise zu den Definitionen der Optionen readable und tainable.

Beispielcode:

function y = func(x, y, varargin)

    [u, v] = process_options(varargin,
                             'u', 0,
                             'v', 1);
1
georg

Inspiriert von Jonas 'Antwort, aber kompakter:

function example(varargin)
  defaults = struct('A',1, 'B',magic(3));  %define default values

  params = struct(varargin{:});
  for f = fieldnames(defaults)',
    if ~isfield(params, f{1}),
      params.(f{1}) = defaults.(f{1});
    end
  end

  %now just access them as params.A, params.B
1
Jotaf
function argtest(varargin)

a = 1;

for ii=1:length(varargin)/2
    [~] = evalc([varargin{2*ii-1} '=''' num2str(varargin{2*ii}) '''']);
end;

disp(a);
who

Dies prüft natürlich nicht auf korrekte Zuweisungen, aber es ist einfach und jede nutzlose Variable wird trotzdem ignoriert. Es funktioniert auch nur für Numerik, Strings und Arrays, nicht jedoch für Matrizen, Zellen oder Strukturen.

0
Tobias Kienzler

Am Ende habe ich das heute geschrieben, und dann habe ich diese Erwähnungen gefunden ... Meine. Es spiegelt im Wesentlichen die Funktionalität von setstructfields () wider, mit der Ausnahme, dass keine neuen Parameter hinzugefügt werden können. Es hat auch eine Option für die Rekursion, wohingegen setstructfields () dies automatisch erledigt . Es kann ein Zellenarray gepaarter Werte aufnehmen, indem struct (args {:}) aufgerufen wird.

% Overlay default fields with input fields
% Good for option management
% Arguments
%   $opts - Default options
%   $optsIn - Input options
%       Can be struct(), cell of {name, value, ...}, or empty []
%   $recurseStructs - Applies optOverlay to any existing structs, given new
%   value is a struct too and both are 1x1 structs
% Output
%   $opts - Outputs with optsIn values overlayed
function [opts] = optOverlay(opts, optsIn, recurseStructs)
    if nargin < 3
        recurseStructs = false;
    end
    isValid = @(o) isstruct(o) && length(o) == 1;
    assert(isValid(opts), 'Existing options cannot be cell array');
    assert(isValid(optsIn), 'Input options cannot be cell array');
    if ~isempty(optsIn)
        if iscell(optsIn)
            optsIn = struct(optsIn{:});
        end
        assert(isstruct(optsIn));
        fields = fieldnames(optsIn);
        for i = 1:length(fields)
            field = fields{i};
            assert(isfield(opts, field), 'Field does not exist: %s', field);
            newValue = optsIn.(field);
            % Apply recursion
            if recurseStructs
                curValue = opts.(field);
                % Both values must be proper option structs
                if isValid(curValue) && isValid(newValue) 
                    newValue = optOverlay(curValue, newValue, true);
                end
            end
            opts.(field) = newValue;
        end
    end
end

Ich würde sagen, dass die Namenskonvention 'default' und 'new' wahrscheinlich besser wäre: P

0
eacousineau

Ich habe eine Funktion erstellt, die auf Jonas und Richie Cotton basiert. Es implementiert sowohl Funktionalitäten (flexible Argumente als auch eingeschränkte, dh nur in den Standardwerten vorhandene Variablen sind zulässig) und einige andere Dinge wie syntaktische Zucker- und Sanitätsprüfungen.

function argStruct = getnargs(varargin, defaults, restrict_flag)
%GETNARGS Converts name/value pairs to a struct (this allows to process named optional arguments).
% 
% ARGSTRUCT = GETNARGS(VARARGIN, DEFAULTS, restrict_flag) converts
% name/value pairs to a struct, with defaults.  The function expects an
% even number of arguments in VARARGIN, alternating NAME then VALUE.
% (Each NAME should be a valid variable name and is case sensitive.)
% Also VARARGIN should be a cell, and defaults should be a struct().
% Optionally: you can set restrict_flag to true if you want that only arguments names specified in defaults be allowed. Also, if restrict_flag = 2, arguments that aren't in the defaults will just be ignored.
% After calling this function, you can access your arguments using: argstruct.your_argument_name
%
% Examples: 
%
% No defaults
% getnargs( {'foo', 123, 'bar', 'qwerty'} )
%
% With defaults
% getnargs( {'foo', 123, 'bar', 'qwerty'} , ...
%               struct('foo', 987, 'bar', magic(3)) )
%
% See also: inputParser
%
% Authors: Jonas, Richie Cotton and LRQ3000
%

    % Extract the arguments if it's inside a sub-struct (happens on Octave), because anyway it's impossible that the number of argument be 1 (you need at least a couple, thus two)
    if (numel(varargin) == 1)
        varargin = varargin{:};
    end

    % Sanity check: we need a multiple of couples, if we get an odd number of arguments then that's wrong (probably missing a value somewhere)
    nArgs = length(varargin);
    if rem(nArgs, 2) ~= 0
        error('NameValuePairToStruct:NotNameValuePairs', ...
            'Inputs were not name/value pairs');
    end

    % Sanity check: if defaults is not supplied, it's by default an empty struct
    if ~exist('defaults', 'var')
        defaults = struct;
    end
    if ~exist('restrict_flag', 'var')
        restrict_flag = false;
    end

    % Syntactic sugar: if defaults is also a cell instead of a struct, we convert it on-the-fly
    if iscell(defaults)
        defaults = struct(defaults{:});
    end

    optionNames = fieldnames(defaults); % extract all default arguments names (useful for restrict_flag)

    argStruct = defaults; % copy over the defaults: by default, all arguments will have the default value.After we will simply overwrite the defaults with the user specified values.
    for i = 1:2:nArgs % iterate over couples of argument/value
        varname = varargin{i}; % make case insensitive
        % check that the supplied name is a valid variable identifier (it does not check if the variable is allowed/declared in defaults, just that it's a possible variable name!)
        if ~isvarname(varname)
          error('NameValuePairToStruct:InvalidName', ...
             'A variable name was not valid: %s position %i', varname, i);
        % if options are restricted, check that the argument's name exists in the supplied defaults, else we throw an error. With this we can allow only a restricted range of arguments by specifying in the defaults.
        elseif restrict_flag && ~isempty(defaults) && ~any(strmatch(varname, optionNames))
            if restrict_flag ~= 2 % restrict_flag = 2 means that we just ignore this argument, else we show an error
                error('%s is not a recognized argument name', varname);
            end
        % else alright, we replace the default value for this argument with the user supplied one (or we create the variable if it wasn't in the defaults and there's no restrict_flag)
        else
            argStruct = setfield(argStruct, varname, varargin{i + 1});  %#ok<SFLD>
        end
    end

end

Auch als Gist erhältlich .

Und für diejenigen, die an echten Namensargumenten interessiert sind (mit einer Python-ähnlichen Syntax, zB: myfunction (a = 1, b = 'qwerty')), verwenden Sie InputParser (nur für Matlab müssen Octave-Benutzer bis v4.2 auf warten.) oder Sie können einen Wrapper namens InputParser2 ) versuchen.

Auch als Bonus, wenn Sie nicht immer argstruct.yourvar eingeben müssen, sondern yourvar direkt verwenden möchten, können Sie das folgende snippet von Jason S verwenden:

function varspull(s)
% Import variables in a structures into the local namespace/workspace
% eg: s = struct('foo', 1, 'bar', 'qwerty'); varspull(s); disp(foo); disp(bar);
% Will print: 1 and qwerty
% 
%
% Author: Jason S
%
    for n = fieldnames(s)'
        name = n{1};
        value = s.(name);
        assignin('caller',name,value);
    end
end
0
gaborous