R 在函数中访问函数中的变量

R 在函数中访问函数中的变量,r,function,parameter-passing,R,Function,Parameter Passing,在R中运行函数时,我在其中运行另一个函数。 我有一个代码在这行: f_a <- function(b, c){ return(b + c) } f_e <- function(){ b = 2 c = 2 d = f_a(b, c) print(d) } 有没有一种方法可以通过使用环境、搜索路径或任何其他方式来实现这一点?我鼓励您阅读, 但我认为避免编写大量变量的好方法可能是: get_args_for <- function(fu

在R中运行函数时,我在其中运行另一个函数。 我有一个代码在这行:

f_a <- function(b, c){
    return(b + c)
}

f_e <- function(){
    b = 2
    c = 2 
    d = f_a(b, c)
    print(d)
}

有没有一种方法可以通过使用环境、搜索路径或任何其他方式来实现这一点?

我鼓励您阅读, 但我认为避免编写大量变量的好方法可能是:

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 
像上面这样的东西在R包中可能不起作用, 因为我认为包的函数的封闭环境是被锁定的

或:


一个选项是从调用环境显式获取
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
不过,这并不是一种真正健壮的代码编写方法,因为它限制了成功调用
fa
的可能方式。遵循显式传递变量的代码要容易得多。

编辑:

@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)
}
另一种方法是只返回一个解析树,然后在“本地”环境中完成对函数的求值。这在我看来是“丑陋的”:


expr\u list您可以将变量分配给全局环境并使用内部函数

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

f_a我的f_a中有很多函数,因此这相当麻烦,相当于将变量作为更可行的选项传递。词法范围界定更有意义,因为词法范围界定不是一种选择,而是R的工作方式。无论如何,我强烈建议您重新思考如何构建代码,因为所有这些方法都会引入奇怪的行为,因为它们都与R查找东西的位置有关。实际上,我正在编写一个包,所有这些函数都是包的一部分。我需要不断地在这些功能之间切换,这就是问题所在。我想将所有环境设置为一个主环境,在这个主环境中,我的所有变量对RTH都是可见的。这听起来仍然是一个非常糟糕的方法,这将导致非常难以调试范围bug。在编写大量使用的代码时,冗长不一定是坏事。除了@alistaire的注释外,编写良好的软件模块还具有和。根据您在OP和评论中的描述,最好花些时间重新设计您的函数,使需要更多交互的东西更紧密地结合在同一个函数中,以增加内聚并减少耦合,或者将数据类型抽象成一个更大粒度的对象,可以在函数之间来回传递。同样,我的f_a中有很多函数,因此这将非常麻烦。词法范围对我来说更有意义,尽管这似乎也是一个很好的选择。使用
quote
expression
而不是
parse
会(稍微)减少ugly@alistair. 同意并删除无关的
return()
。使用全局环境不是我的选项,而是b、c全局常量、参数、对象属性或任意变量。。。?如果您经常需要从某些函数中访问某些变量,那么它应该是一个对象,这难道不是一种强烈的代码味道吗?
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
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 
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
f_a <- function(){
    eval(quote(b + c), parent.frame())
}
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)
}
 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)
}
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