在R中将缺少的参数从函数传递到函数
Posted
技术标签:
【中文标题】在R中将缺少的参数从函数传递到函数【英文标题】:Passing missing argument from function to function in R 【发布时间】:2015-10-12 00:20:13 【问题描述】:我了解到在函数中使用可选参数并使用 missing() 检查它们是一种常见的做法 (例如SO 22024082 中讨论的)
在本例中,round0 是可选参数(我知道,round0 可以定义为逻辑参数)。
foo = function(a, round0)
a = a * pi
if(!missing(round0)) round(a)
else a
但是如果我从另一个函数调用这个函数,我怎么能传递“缺失”呢?
bar = function(b)
if(b > 10) round1=T
foo(b, round1)
如果 b
foo = function(a, round0)
a = a * pi
print(missing(round0))
print(round0)
if(!missing(round0)) round(a)
else a
并运行 bar(9) 输出为:
bar(9)
[1] FALSE
Error in print(round0) : object 'round1' not found
Called from: print(round0)
也就是说:round0没有丢失,但也无法访问?
我不想在 bar() 中使用不同的函数调用,如果 foo() 中有多个可选参数,我将不得不为每个丢失/未丢失的所有可选参数的组合编写一个函数调用。
是否可以通过“缺失”,或者其他解决方案适用于这个问题?
【问题讨论】:
通常,如果你以特定的形式调用一个函数,你应该确保你有所有的参数。在这里,我将在bar
的开头添加一个round1=F
,并将foo
更新为if(!missing(round0) && round0)
。缺少允许你调用foo(a)
或foo(a,T/F)
,如果你用两个参数调用它,第二个参数不会丢失并且必须是可解析的。
我的猜测是missing
在表示函数参数的承诺对象具有非空表达式槽时立即返回FALSE
。在修改后的foo
函数中在a = a * pi
之后添加行print(substitute(round0))
,然后执行foo(9)
。 substitute
将提取表达式槽。它不会打印任何内容,即round0
的空表达式槽。现在试试bar(9)
。这将打印round1
。但是当您使用print
时,R 将尝试评估尚未定义的round1
(惰性评估)。
【参考方案1】:
在您的示例中,round0 没有丢失,它设置为未定义的 round1
(与丢失相反)。
一般而言,最好的方法是使用默认值,在您的情况下为FALSE
:
foo = function(a, round0 = FALSE)
a = a * pi
if (!round0) round(a)
else a
bar = function(b)
round1 <- FALSE
if (b > 10) round1=TRUE
foo(b, round1)
或者默认值在参数列表中不容易表达的地方:
foo = function(a, round0 = NULL)
a = a * pi
if(!is.null(round0)) round(a)
else a
bar = function(b)
round1 <- NULL
if (b > 10) round1=TRUE
foo(b, round1)
请注意,在这两种情况下,您都需要在调用函数中手动将参数设置为默认值。
如果需要,您还可以在 if
语句中调用带有或不带参数的 foo
函数:
bar = function(b)
if (b > 10) foo(b, TRUE) else foo(b)
@moody_mudskipper 的answer 展示了另一种显示如何生成缺失值的方法。
【讨论】:
最后的说法不准确。您可以通过将变量定义为quote(expr=)
、substitute()
或alist(x=1)[[1]]
来使变量丢失。前者效率最高。 rlang 有一个 missing_arg
函数,它也有同样的作用。请参阅下面我自己的答案。
@Moody_Mudskipper 谢谢,我不知道。我已经修改了我的答案以指向你的答案。【参考方案2】:
我最近遇到了类似的问题,想用一般的方式解决。我觉得可以按照下面函数g()
的定义来做:
f <- function(a = 5, b = 3, c = 2, d = 7)
if (missing(a)) print("a is missing.")
if (missing(b)) print("b is missing.")
if (missing(c)) print("c is missing.")
if (missing(d)) print("d is missing.")
cat(a, b, c, d)
g <- function(a = 1, b = 1, c = 1, d = 1)
args <- as.list(match.call())
args[[1]] <- NULL # remove first list element, it's the function call
do.call(f, args, envir = parent.frame())
以下是我们在使用不同的参数集调用 g()
时得到的结果:
> g()
[1] "a is missing."
[1] "b is missing."
[1] "c is missing."
[1] "d is missing."
5 3 2 7
> g(a = 3)
[1] "b is missing."
[1] "c is missing."
[1] "d is missing."
3 3 2 7
> g(b = 10, c = 10)
[1] "a is missing."
[1] "d is missing."
5 10 10 7
如果您不想将所有参数交给下一个函数或想添加一些参数,您可以添加到args
列表或从列表中删除。例如,请参阅以下函数 g()
,它以一般方式执行此操作:
g <- function(a = 1, b = 1, c = 1, x = 1, y = 1, z = 1)
f_args <- c("a", "b", "c") # arguments we want to hand off to function f
# obtain the list of arguments provided
args <- as.list(match.call())
# remove first list element, it's the function call
args[[1]] <- NULL
# remove the arguments that are not listed in f_args
args <- args[na.omit(match(f_args, names(args)))]
# now add argument d, we always want it to be 0:
args <- c(args, list(d = 0))
do.call(f, args, envir = parent.frame())
以下是我们在使用不同的参数集调用 g()
时得到的结果:
> g()
[1] "a is missing."
[1] "b is missing."
[1] "c is missing."
5 3 2 0
> g(a = 3)
[1] "b is missing."
[1] "c is missing."
3 3 2 0
> g(b = 10, c = 10)
[1] "a is missing."
5 10 10 0
有关do.call()
的更多信息,请参阅this answer。
【讨论】:
【参考方案3】:您可以使用 substitute()
不带参数来创建缺失对象。
在您的情况下,我们可以在 else
子句中将 round1
设为缺失对象:
foo = function(a, round0)
a = a * pi
if(!missing(round0)) round(a)
else a
bar = function(b)
if(b > 10) round1=T else round1 <- substitute()
foo(b, round1)
bar(9)
#> [1] 28.27433
由reprex package (v0.3.0) 于 2019 年 10 月 24 日创建
【讨论】:
missing()
需要它的输入是某种东西(它的名字在这方面是矛盾的)。这个东西是一个空表达式,看起来substitute()
可以创建一些,你也可以做alist(x=)[[1]]
。对于冗长的答案,我们需要进入 C 实现,我对此了解不多。【参考方案4】:
rlang
还提供了一个函数missing_arg()
,它可以使参数丢失。
foo = function(a, round0)
a = a * pi
if(!missing(round0)) round(a)
else a
bar = function(b)
if(b > 10) round1 <- TRUE else round1 <- rlang::missing_arg()
foo(b, round1)
foo(9)
#> [1] 28.27433
bar(9)
#> [1] 28.27433
由reprex package 创建于 2020-12-02 (v0.3.0)
【讨论】:
以上是关于在R中将缺少的参数从函数传递到函数的主要内容,如果未能解决你的问题,请参考以下文章
将变量名称作为参数从外部函数传递到 R 中的内部函数时出现问题?