【问题标题】:How to get an R function's default values from the calling environment, not the enclosing environment如何从调用环境而不是封闭环境中获取 R 函数的默认值
【发布时间】:2021-11-04 18:25:46
【问题描述】:

嵌套 source()-ed 文件时,函数内的 R assign() 失败,但 assign() 可以自己工作。

我的小组有许多调用其他程序的 R 程序。我们创建了一个 getObjectFromCalledProgram() 函数来与 source(..., local = calledProgram

有人能解释一下为什么我们的 getObjectFromCalledProgram() 函数(它非常简单地使用了 assign() 函数)在一个 source()-ed 程序中失败,而直接使用的 assign 函数可以工作吗?

这是一个例子。看看exists("subSourceMeObject")在getObjectFromCalledProgram()函数后返回FALSE,而在assign()函数后返回TRUE:

## Program1 ##
getObjectFromCalledProgram <-function(objectName) assign(x=objectName, value=calledProgram[[objectName]], env = parent.frame())

# set up the program files to be source()-ed
Program3 <- tempfile()  # this program will be called (source()-ed) within a source()-ed program.
writeLines(c('  ## Program3 ## ','  Program3Object <- "object3" '), con=Program3)

Program2 <- tempfile()     # this will be the secondary program, called (source()-ed) by this main program.
writeLines(c(' ## Program2 ##                                                '
             , ' Program2Object <- "object2"                                   '
             , ' source(Program3, local=calledProgram <- new.env(), echo = T)  '
             , ' # Use getObjectFromCalledProgram() to put subSourceMeObject into Program2\'s environment.'           
             , ' (getObjectFromCalledProgram("Program3Object"))                '
             , ' # That DOES NOT WORK. It returns NULL. I.e., the assign() within getObjectFromCalledProgram() fails.'
             , ' exists("Program3Object")  # returns FALSE                     '
             , ' # Use assign() directly rather than within the Program3Object function. WORKS.'
             , ' (assign("Program3Object", calledProgram[["Program3Object"]])) '
             , ' exists("Program3Object")  # returns TRUE                      '
             , ' # That WORKS. It returns "object2". I.e., the assigs() function did pull Program3Object into Program2\'s environment. '
)
, con=Program2
)

# source() those program files.
source(Program2, local=calledProgram <- new.env(), echo = T)
# Pull the created Program2Object and Program3Object into Program1's unlist(lapply(c("Program2Object", "Program3Object"), exists))  # the objects don't exist in Program1's environment.
environment, to show that getObjectFromCalledProgram() works.
(getObjectFromCalledProgram("Program2Object"))  # put Program2Object into Program1's environment.
(getObjectFromCalledProgram("Program3Object"))  # put Program3Object into Program1's environment.
unlist(lapply(c("Program2Object", "Program3Object"), exists))  # the objects now exist in Program1's environment.
rm(getObjectFromCalledProgram, Program2, Program3, Program2Object, Program3Object)  # Clean up.

【问题讨论】:

  • 写一个包

标签: r nested assign


【解决方案1】:

感谢https://stackoverflow.com/a/49385368/3799203,我想通了。而不是myArg = rObject,我需要使用myArg = parent.frame()$rObject,告诉R在调用环境中寻找rObject,而不是在封闭环境中寻找(即,而不是在创建函数的环境中寻找)。

详情:从http://adv-r.had.co.nz/Environments.html#function-envs 我了解到,在 R 中,函数默认值取自函数的封闭环境,而不是调用环境(调用函数的环境)。我猜在创建包时“查看包含环境”的方法很方便,因为它可以让函数在同一个包中找到其他东西。

# Simple example: x in myArg=x uses the x object in the enclosing environment, i.e., the environment where myF was created.
myF <- function(myArg=x) {print(paste("myF returns:",myArg))}
x <- "x from enclosing environment"
myF()
#> [1] "myF returns: x from enclosing environment"
with(env2<-new.env(), {
  x <- "x from calling environment"
  myF()  # returns the value of x from in the environment where the function was created.
  myF(myArg=x)  # If I explicitly pass a value to the myArg argument, R starts its search for x from the current environment.
})
#> [1] "myF returns: x from enclosing environment"
#> [1] "myF returns: x from calling environment"
rm(x, myF, env2)

# Use parent.frame()$... to have the default argument values set by the calling environment rather than by the containing environment:
myF <- function(myArg=parent.frame()$x) {print(paste("myF returns:",myArg))}
x <- "x from enclosing environment"
myF()
#> [1] "myF returns: x from enclosing environment"
with(env2<-new.env(), {
  x <- "x from calling environment"
  myF()  # the function used "parent.frame()$x" as the default value, R starts its search for x from the calling environment (the environment where the function was executed).
  myF(myArg=x)
})
#> [1] "myF returns: x from calling environment"
#> [1] "myF returns: x from calling environment"
rm(x, myF, env2)

reprex package (v2.0.1) 于 2021 年 10 月 15 日创建

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-09
    • 1970-01-01
    • 2021-06-10
    相关资源
    最近更新 更多