使用可选的命名参数定义函数的最佳/规范方法是什么?为了使其具体化,让我们创建一个带有命名参数foo
,a
和b
的函数c
,它们分别默认为1,2和3。为了比较,这里是带有位置参数的foo
版本:
foo[a_:1, b_:2, c_:3] := bar[a,b,c]
以下是foo
的命名参数版本的示例输入和输出:
foo[] --> bar[1,2,3]
foo[b->7] --> bar[1,7,3]
foo[a->6, b->7, c->8] --> bar[6,7,8]
在命名参数之前使用位置参数当然也很容易。
答案 0 :(得分:11)
我在Mathematica文档中找到了标准方法:http://reference.wolfram.com/mathematica/tutorial/SettingUpFunctionsWithOptionalArguments.html
Options[foo] = {a->1, b->2, c->3}; (* defaults *)
foo[OptionsPattern[]] := bar[OptionValue@a, OptionValue@b, OptionValue@c]
每次输入“OptionValue”都有点麻烦。出于某种原因,您不能只创建像ov = OptionValue
这样的全局缩写,但您可以这样做:
foo[OptionsPattern[]] := Module[{ov},
ov[x___] := OptionValue[x];
bar[ov@a, ov@b, ov@c]]
或者这个:
With[{ov = OptionValue},
foo[OptionsPattern[]] := bar[ov@a, ov@b, ov@c]
]
或者这个:
$PreRead = ReplaceAll[#, "ov" -> "OptionValue"] &;
foo[OptionsPattern[]] := bar[ov@a, ov@b, ov@c]
答案 1 :(得分:6)
是的,OptionValue
可能有点棘手,因为它依赖于一块魔法,所以
OptionValue[name]
相当于OptionValue[f,name]
,其中f
是OptionValue[name]
出现的转化规则左侧的头部。
投入一个明确的Automatic
通常可以解决问题,所以在你的情况下我会说解决方案是:
Options[foo] = {a -> 1, b -> 2, c -> 3};
foo[OptionsPattern[]] :=
bar @@ (OptionValue[Automatic, #] &) /@ First /@ Options[foo]
顺便说一下,选项过去通过匹配opts:___?OptionQ
完成,然后手动查找选项值为{a,b,c}/.Flatten[{opts}]
。模式检查OptionQ
仍然存在(尽管没有记录),但OptionValue
方法的优势在于您可以获得不存在选项的警告(例如foo[d->3]
)。这也是您第二次回复的情况,但不适用于您接受的回复。
答案 2 :(得分:1)
我会把这个可能的解决方案投入到混合中:
foo[opts___Rule] := Module[{f},
f@a = 1; (* defaults... *)
f@b = 2;
f@c = 3;
each[a_->v_, {opts}, f@a = v];
Return[bar[f@a, f@b, f@c]]
]
我喜欢它的简洁,但我认为这不是标准方式。这样做有什么陷阱吗?
PS,它使用以下方便的实用功能:
SetAttributes[each, HoldAll]; (* each[pattern, list, body] *)
each[pat_, lst_, bod_] := (* converts pattern to body for *)
Scan[Replace[#, pat:>bod]&, Evaluate@lst] (* each element of list. *)