Allowing unknown parameters in an inputParser

29 次查看(过去 30 天)
Hello, I am attempting to figure out a better way of handling parameters and passing them through input parsers. Let us say I have three parameters, and I will store them in a struct, and then pass that struct as the arguments to multiple input parsers that DON'T explicitly include the stated variables without it throwing errors.
params = struct(...
'type','fruit',...
'name','banana',...
'price',3.14)
Ok, now lets say I want to hand this as the parameters to two different functions. This first one sets a default price for some reason,
function tot = myFun1(n,varargin)
defaultPrices = struct(...
'apple',ln(1),...
'banana',sqrt(-1),...
'orange',3.14);
p = inputParser
addParameter(p,'name','orange',@(x) ismember(x,{'apple','orange','banana'}));
addParameter(p,'price',[])
p = parse(p,varargin{:})
price = p.Results.price;
if isempty(price)
price = defaultPrices.(p.Results.name);
end
tot = n*price;
end
and this second one lets say pulls up a picture.
function myFun2(varargin)
defaultImage = 'ErrorScreen.png'
p = inputParser;
addParameter(p,'type',[]);
addParameter(p,'name',[]);
parse(p,varargin{:})
try
im = imload(fullfile(pwd,p.Results.type,p.Results.name));
catch
im = imload(defaultImage);
end
imshow(im);
end
Ok, now for the two functions above I want to be able to call both with the same params structure:
tot = myFun1(1E6,params);
myFun2(params);
However, this will lead to an error in both functions; the first because 'type' is not explicitly included in the input parser, "'type' is not a recognized parameter. For a list of valid name-value pair arguments, see the documentation for this function.", and similarly for myFun2 due to 'price.
So, my question is whether (A) there is a way to get the parser to be more tolerant of unexpected input fields, so I can do the above, or (B) if there is some other "best practices" method so that I can avoid creating multiple params structures with redundant fields, or duplicating the structure, and then cycling through 'rmfield's before input. Neither is terribly elegant, and I am trying to avoid lots of 'addParameter's for params that I don't actually need in a specific function just to avoid the error.
The above is just a goofy MWE of what I am trying to code, help is appreciated.
  2 个评论
D. Plotnick
D. Plotnick 2018-4-16
编辑:D. Plotnick 2018-4-16
As a follow-up: being able to add an empty argument as the input validator would also be helpful. In that case, we could instead use an nX3 cell array and a loop to construct our parser: e.g.
defaults = {...
'type','fruit',@(x) ismember(x,allowedTypes) ; ...
'name','orange',[]; ...
'price',3.14, []};
for i = 1:size(defaults,1)
addParameter(p,defaults{i,1},defaults{i,2},defaults{i,3});
end
Using the cell technique would allow me to carry around a set of 'default function parameters'. However, the above results in the error "Validator must be a function handle." I suppose I could just create a dummy function...but again that is pretty kludgy.
D. Plotnick
D. Plotnick 2018-4-16
Follow up to my follow up: apparently using '@true' will act as a valid dummy function in the cell array.

请先登录,再进行评论。

采纳的回答

Matt J
Matt J 2018-4-16
编辑:Matt J 2018-4-16

You can set the inputParser object's KeepUnmatched property to true

p = inputParser;
p.KeepUnmatched=true;
addParameter(p,...)

This way, no error will be thrown if an unexpected parameter name is passed. It is a dangerous practice, however. If you make a spelling mistake in your params input, you will be passing incorrect parameter values unwittingly.

  2 个评论
D. Plotnick
D. Plotnick 2018-4-16
Thanks, and yes I can see that being a danger, since it will automatically use the default value without further notification.
D. Plotnick
D. Plotnick 2018-4-17
I have opted to use my cell array strategy outlined above. Extraneous values wind up in the p.Results field in each function, but they appear to be handles to the original variables rather than copies, so there isn't any memory bloat (please correct me if I'm wrong). I then pull the needed values out of p.Results for each function. This has the advantage of allowing me to declare all of my default parameters in a single script, rather than have them set at the top of each function. There will be issues if I wanted, say, two different function dependent defaults for the same named parameter, but overall its a better strategy and less prone to developer error.

请先登录,再进行评论。

更多回答(1 个)

Matt J
Matt J 2018-4-17
编辑:Matt J 2018-4-17

(B) if there is some other "best practices" method so that I can avoid creating multiple params structures with redundant fields

An alternative would be to use a tree of nested structures,

 allParams.myFun1.name =...
 allParams.myFun1.price =...
 allParams.myFun2.name =...
 allParams.myFun2.type =...

and make function calls like

   tot = myFun1(1E6,allParams.myFun1);
   myFun2(allParams.myFun2)

This involves no more storage than the total number of default parameters across the different functions. It also avoids name conflict between functions with the same parameter names.

类别

Help CenterFile Exchange 中查找有关 Argument Definitions 的更多信息

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by