在R中运行一个函数时,我在其中运行另一个函数。 我有这样的代码:
f_a <- function(b, c){
return(b + c)
}
f_e <- function(){
b = 2
c = 2
d = f_a(b, c)
print(d)
}
这很好。我想做的是不将变量 b, c
传递给函数f_a
。我想做这样的事情(会引发错误)
f_a <- function(){
return(b + c)
}
f_e <- function(){
b = 2
c = 2
d = f_a()
print(d)
}
是否可以使用环境或搜索路径或其他任何方式来做到这一点?
答案 0 :(得分:9)
我鼓励您阅读有关lexical scoping的信息, 但我认为避免写入大量变量的好方法可能是:
get_args_for <- function(fun, env = parent.frame(), inherits = FALSE, ..., dots) {
potential <- names(formals(fun))
if ("..." %in% potential) {
if (missing(dots)) {
# return everything from parent frame
return(as.list(env))
}
else if (!is.list(dots)) {
stop("If provided, 'dots' should be a list.")
}
potential <- setdiff(potential, "...")
}
# get all formal arguments that can be found in parent frame
args <- mget(potential, env, ..., ifnotfound = list(NULL), inherits = inherits)
# remove not found
args <- args[sapply(args, Negate(is.null))]
# return found args and dots
c(args, dots)
}
f_a <- function(b, c = 0, ..., d = 1) {
b <- b + 1
c(b = b, c = c, d = d, ...)
}
f_e <- function() {
b <- 2
c <- 2
arg_list <- get_args_for(f_a, dots = list(5))
do.call(f_a, arg_list)
}
> f_e()
b c d
3 2 1 5
默认情况下设置inherits = FALSE
可确保我们仅从指定的环境中获取变量。
我们还可以在调用dots = NULL
时设置get_args_for
,以免传递所有变量,
但是将省略号留空。
尽管如此,它并不完全健壮,
因为dots
仅附加在末尾,
如果某些参数未命名,
他们最终可能会与职位相匹配。
另外,如果呼叫中的某些值应为NULL
,
很难检测到它。
我强烈建议您不要在R包内使用以下内容。 不仅会很丑, 您会从R的CMD检查中获得关于未定义的全局变量的大量注释。
其他选项。
f_a <- function() {
return(b + c)
}
f_e <- function() {
b <- 2
c <- 2
# replace f_a's enclosing environment with the current evaluation's environment
environment(f_a) <- environment()
d <- f_a()
d
}
> f_e()
[1] 4
在R包中,上述类似内容可能无法正常工作, 因为我认为程序包的功能已锁定其封闭环境。
或者:
f_a <- function() {
with(parent.frame(), {
b + c
})
}
f_e <- function() {
b <- 2
c <- 2
f_a()
}
> f_e()
[1] 4
这样一来,您就不会永久修改另一个函数的封闭环境。 但是,这两个功能将共享一个环境, 这样可能会发生:
f_a <- function() {
with(parent.frame(), {
b <- b + 1
b + c
})
}
f_e <- function() {
b <- 2
c <- 2
d <- f_a()
c(b,d)
}
> f_e()
[1] 3 5
在调用内部函数时会修改外部环境中的值。
还有一个更灵活的选择,
因为它仅使用eval
临时修改了封闭环境。
但是,某些R函数可以通过“ daRk magic”检测其当前执行环境,
并且不能被eval
欺骗;
参见this discussion。
f_a <- function() {
b <- b + 1
b + c
}
f_e <- function() {
b <- 2
c <- 2
# use current environment as enclosing environment for f_a's evaluation
d <- eval(body(f_a), list(), enclos=environment())
c(b=b, d=d)
}
> f_e()
b d
2 5
答案 1 :(得分:3)
一种选择是从调用环境中显式获取a
和b
:
f_a <- function(){
get('b', envir = parent.frame()) + get('c', envir = parent.frame())
}
f_e <- function(){
b = 2
c = 2
d = f_a()
d
}
f_e()
#> [1] 4
或者,您可以使用quote
来延迟评估,然后使用eval
来评估调用环境中的代码,有效地执行相同的操作:
f_a <- function(){
eval(quote(b + c), parent.frame())
}
但是,这实际上不是一种强大的代码编写方法,因为它限制了成功调用f_a
的可能方法。遵循显式传递变量的代码要容易得多。
答案 2 :(得分:2)
编辑:
@alistaire建议使用quote
来构造表达式,这提出了似乎更丑陋的另一种选择:
expr_env <- new.env()
expr_env$f_a <- quote(b+c)
expr_env$f_z <- quote(x+y)
f_e<-function(){
b=2
c=2
d=eval( expr_env$f_a)
print(d)
}
是否可以使用local
定义函数?
f_e<-function(){
b=2
c=2
d<-local({
b+c
})
print(d)
}
f_e()
[1] 4
另一种选择是只返回一个分析树,然后在函数的“本地”环境中完成评估。对我来说这似乎“丑陋”:
expr_list<-function(){ f_a <- quote(b+c)
f_z <- quote(x+y)
list(f_a=f_a,f_z=f_z) }
f_e<-function(){
b=2
c=2
d=eval( (expr_list()$f_a))
print(d)
}
答案 3 :(得分:0)
您可以将变量分配给全局环境并在内部函数中使用。
f_a <- function(){
return(b + c)
}
f_e <- function(){
assign("b", 2, envir = .GlobalEnv)
assign("c", 2, envir = .GlobalEnv)
d = f_a()
print(d)
}
# > f_e()
# [1] 4