使用可选的命名参数定义函数的最佳/规范方法是什么?为了使它具体化,让我们用命名参数 a b c 创建一个函数 foo ,默认情况下分别为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]

在命名参数之前使用位置参数当然也很容易。

有帮助吗?

解决方案

我在Mathematica文档中找到了标准方法: http://参考.wolfram.com /数学/教程/ 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]

其他提示

是的, 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] 

顺便说一下,过去通过匹配选项来完成选项:___?OptionQ ,然后手动查找选项值为 {a,b,c} /。Flatten [{ OPTS}] 。模式检查 OptionQ 仍然存在(虽然未记录),但 OptionValue 方法的优点是您可以获得不存在选项的警告(例如 foo [ D-→3] )。这也是您第二次回复的情况,但不适用于您接受的回复。

我会把这个可能的解决方案投入到混合中:

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.       *)
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top