【问题标题】:How does the envir option of do.call work?do.call 的 envir 选项如何工作?
【发布时间】:2018-05-23 21:11:29
【问题描述】:

do.call 的文档指出:

如果quoteFALSE,默认值,则计算参数(在调用环境中,而不是在envir 中)。

这句话告诉我,当quote = FALSE 时,指定envir 没有区别。然而,事实并非如此,事实上我遇到过需要指定envir 才能使函数工作的情况。

最简单的可重现示例:

g1 <- function(x) {
  args <- as.list(match.call())
  args[[1]] <- NULL # remove the function call
  do.call(print, args, quote = FALSE) # call print()
}

g2 <- function(x) {
  args <- as.list(match.call())
  args[[1]] <- NULL # remove the function call
  do.call(print, args, quote = FALSE, envir = parent.frame()) # call print(), specifying envir
}

h1 <- function(x, y) {
  g1(x*y)
}

h2 <- function(x, y) {
  g2(x*y)
}

有了这些功能,h2() 的行为就像人们想象的那样,但h1() 却没有:

h1(2, 3)
#Error in print(x) : object 'y' not found

h2(2, 3)
#[1] 6

y <- 100
h1(2, 3)
#[1] 600 
## Looks like g1() took the value of y from the global environment

h2(2, 3)
#[1] 6

谁能给我解释一下这里发生了什么?

注意:有一个相关的帖子here,但我阅读的答案并没有具体说明do.call()envir 变量的作用。

【问题讨论】:

    标签: r


    【解决方案1】:

    ?do.call 说:

    环境
    评估呼叫的环境。这将成为;这将是 如果什么是字符串并且参数是最有用的 符号或引用的表达式。

    如果do.callwhat= 参数是一个字符串,我们可以很容易地说明这一点。然后envir= 确定查找位置。

    e <- new.env()
    e$f <- function() 2
    f <- function() 3
    do.call("f", list())
    ## [1] 3
    do.call("f", list(), envir = e)
    ## [1] 2
    

    问题中的代码显示的参数也是如此。请注意,由于使用了match.call(),因此参数已被引用。

    h1g1 的情况下发生的情况是它在g1 内有效运行

    do.call(print, list(call("*", quote(x), quote(y))), quote = FALSE)
    

    现在它在g1 中找到x(因为g1 有一个参数x)但在g1 中没有y,因此它查找g1 的父环境,即它找到y的全局环境。

    对于h2g2,它在g2 中运行:

    do.call(print, list(call("*", quote(x), quote(y))), quote = FALSE, envir = parent.frame())
    

    它在h2 中找到xy,这是g2 的父框架。

    注意,父环境与父框架不同:

    • 父环境由函数定义的位置决定,所以如果函数是在全局环境中定义的,那么它的父环境就是全局环境。
    • 父框架是调用者的环境

    【讨论】:

    • 谢谢。所以我认为quote=FALSE 对这种情况没有影响,如果我想模拟常规函数调用,g2 中的调用是正确的方法吗?
    猜你喜欢
    • 1970-01-01
    • 2013-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-24
    • 2011-07-31
    • 2014-05-30
    相关资源
    最近更新 更多