访问函数内函数中的变量

Sid*_*ddd 8 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)
}
Run Code Online (Sandbox Code Playgroud)

这很好用.我想做的是不将变量传递 b, c给函数f_a.我想做这样的事情(抛出错误)

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

f_e <- function(){
    b = 2
    c = 2
    d = f_a()
    print(d)
}
Run Code Online (Sandbox Code Playgroud)

有没有办法使用环境或搜索路径或任何其他方式?

Ale*_*xis 11

我鼓励你阅读有关词法范围的内容,但我认为避免编写大量变量的好方法可能是:

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 
Run Code Online (Sandbox Code Playgroud)

设置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
Run Code Online (Sandbox Code Playgroud)

像上面这样的东西可能在R包中不起作用,因为我认为包的功能已经锁定了它们的封闭环境.

要么:

f_a <- function() {
    with(parent.frame(), {
        b + c
    })
}

f_e <- function() {
    b <- 2
    c <- 2
    f_a()
}

> f_e()
[1] 4
Run Code Online (Sandbox Code Playgroud)

这样您就不会永久修改其他功能的封闭环境.但是,这两个函数都将共享一个环境,因此可能会发生以下情况:

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
Run Code Online (Sandbox Code Playgroud)

调用内部函数的地方修改外部环境中的值.

另一种选择更灵活,因为它只是通过使用临时修改封闭环境eval.但是,某些R函数通过"daRk magic"检测其当前的执行环境,并且不能被愚弄eval; 看到这个讨论.

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 
Run Code Online (Sandbox Code Playgroud)