我有一个像
这样的功能myfunc <- function(x, y=x){
x+y
}
如果y没有传递给函数,那么(显然)将y的值默认为x。
现在,我使用optparse
读取一些调用myfunc
的脚本的命令行参数。
# myscript.R
option_list <- list(
make_option(c("--x"), type="numeric"),
make_option(c("--y"), type="numeric")
)
print(myfunc(opt$x, opt$y))
上面代码的问题是,它强制用户为y提供一个值(否则会抛出错误)。相反,我想使用所有且仅使用用户提供的参数来呼叫myfunc
。如何以最优雅,可扩展,通用的方式实现这一目标?
注意 - 对于那些熟悉Python的人,我想我想要使用opt
内的任何值来执行与字典解包类似的操作。
答案 0 :(得分:3)
如果您有optparse
中要提供给函数的参数的命名列表,则可以使用do.call
执行此操作:
# Provide x and y
opts <- list(x=2, y=3)
do.call(myfunc, opts)
# [1] 5
# Provide only x
opts <- list(x=2)
do.call(myfunc, opts)
# [1] 4
正如您所说,这基本上来自Python的"dictionary unpacking"/"splatting"。
然后,您可以使用optparse
来获取x和y的值,使y成为命令行上的可选输入:
# optparse.R
library(optparse)
option_list <- list(make_option("--x", type="integer", default=0),
make_option("--y", type="integer"))
opt <- parse_args(OptionParser(option_list=option_list))
myfunc <- function(x, y=x) x+y
do.call(myfunc, opt[names(opt) %in% c("x", "y")])
# > Rscript optparse.R --x=2 --y=3
# [1] 5
# > Rscript optparse.R --x=2
# [1] 4
通过使用被调用的R函数来计算y的默认值而不是命令行解析器,为y创建更复杂的默认值很简单,例如y=min(0, x)
。
# optparse.R
library(optparse)
option_list <- list(make_option("--x", type="integer", default=0),
make_option("--y", type="integer"))
opt <- parse_args(OptionParser(option_list=option_list))
myfunc <- function(x, y=min(0, x)) x+y
do.call(myfunc, opt[names(opt) %in% c("x", "y")])
# > Rscript optparse.R --x=-2
# [1] -4
# > Rscript optparse.R --x=2
# [1] 2
答案 1 :(得分:2)
我更喜欢较docopt而不是optparse,因为我发现docopt是
这是一个最小的示例,它还提供了默认值,这是您关心的问题。首先是代码:
#!/usr/bin/Rscript
library(methods) # as Rscript does not load it
library(docopt)
## simple helper function
myfunc <- function(x, y) as.numeric(x) + as.numeric(y)
doc <- "Usage: myscript [-x x] [-y y]
-x x Numeric value for x [default: 0.0]
-y y Numeric value for y [default: -7.89]"
opt <- docopt(doc)
print(myfunc(opt$x, opt$y))
然后用法:
edd@max:/tmp$ ./myscript.R --help
Usage: myscript [-x x] [-y y]
-x x Numeric value for x [default: 0.0]
-y y Numeric value for y [default: -7.89]
edd@max:/tmp$ ./myscript.R
[1] -7.89
edd@max:/tmp$ ./myscript.R -y 40 -x 2
[1] 42
edd@max:/tmp$
请注意,我们必须对值使用as.numeric()
,因为docopt没有做的一件事就是保证/强制执行某种类型。