r - 如何确保参数是按名称而不是按位置调用的?
问题描述
我正在维护一个以单个函数为中心的包,其中包含一些强制性参数以及许多可选参数。
随着我的函数的成熟,可选参数的顺序正在发生变化,因此按顺序调用它们会导致重大变化。
如果后面的这些参数是按位置而不是按名称调用的,我想抛出一个警告/错误(不确定什么是最好的)。
这是一些具有预期输出的伪代码:
crosstable = function(data, cols=NULL, ..., by=NULL, opt1=FALSE, opt2=FALSE, opt3=FALSE){
warn_if_unnamed(by)
stop_if_unnamed(opt1)
stop_if_unnamed(opt2)
stop_if_unnamed(opt3)
doStuff(data, cols, by, opt1, opt2, opt3)
}
crosstable(mtcars, c(cyl, am), by=vs, opt3=TRUE) #OK
crosstable(mtcars, c(cyl, am), by=vs, TRUE) #error as `opt1` might become `opt56` in the future
crosstable(mtcars, c(cyl, am), vs, opt2=TRUE) #warning (?) as `by` will not move but it would be clearer
我怎样才能做到这一点?
编辑:
感谢@user2554330 和其他一些 SO 帖子(here),我终于让它工作了,尽管如果与管道一起使用它就无法工作:
warn_if_unnamed <- function(argname){
.call = sys.call(-1)
f = get(as.character(.call[[1]]), mode="function", sys.frame(-2))
mc = names(as.list(match.call(definition=f, call=.call))) #https://stackoverflow.com/a/17257053/3888000
sc = names(as.list(.call))
if(argname %in% mc && !argname %in% sc){
warning(argname," is referenced by position, not name")
}
}
myfun = function(x, y=NULL, opt1=FALSE, opt2=FALSE, opt3=FALSE){
warn_if_unnamed("opt1")
warn_if_unnamed("opt2")
warn_if_unnamed("opt3")
invisible()
}
myfun(1, 2)
myfun(1, 2, T, opt2=1)
#> Warning in warn_if_unnamed("opt1"): opt1 is referenced by position, not name
myfun(1, 2, opt1=T, 1, opt3)
#> Warning in warn_if_unnamed("opt2"): opt2 is referenced by position, not name
#> Warning in warn_if_unnamed("opt3"): opt3 is referenced by position, not name
myfun(1, 2, opt2=T, 1, opt3)
#> Warning in warn_if_unnamed("opt1"): opt1 is referenced by position, not name
#> Warning in warn_if_unnamed("opt1"): opt3 is referenced by position, not name
由reprex 包于 2021-10-20 创建(v2.0.1)
不过,我可能会进行一些重构以将警告集中到一个警告中。
PS:最后一行看起来像reprex()
.
解决方案
您可以使用该sys.call()
函数来查看您的函数是如何被调用的,并match.call()
查看 R 如何将实参与形参匹配。所以代码
warn_if_unnamed(by)
将是:
if ("by" %in% names(as.list(match.call())) &&
!"by" %in% names(as.list(sys.call())))
warning("'by' should be named")
可以把它放在一个函数中;您需要使用where
参数来sys.call()
查看match.call()
函数调用者的参数,而不是warn_if_unnamed
自身的参数。
推荐阅读
- php - 我正在尝试通过表单发送 id 但提交不起作用
- excel - 如何使用通配符在 Excel 工作表中使用查找和替换?
- github - GraphQL 和 Github
- vue.js - 为什么 beforeEach() 取消了组件内部触发的导航?
- python - 没有名为“本地时间”的过滤器
- javascript - 在 React 中遍历对象
- mysql - 如何在不重复记录的情况下透视 Mysql 数据。我使用了 group by,但没有得到我想要的结果
- python - 根据字符串元素的字符对 Numpy 数组进行切片
- javascript - ReactJS-> 变量未在函数之外更新
- chef-infra - 厨师从本地目录中提取