Allowing unknown parameters in an inputParser

조회 수: 28 (최근 30일)
D. Plotnick
D. Plotnick 2018년 4월 16일
편집: Matt J 2018년 4월 17일
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