【问题标题】:Access R objects created in function访问在函数中创建的 R 对象
【发布时间】:2020-04-29 22:32:27
【问题描述】:

我正在尝试将something 放在 CRAN 上,它允许用户通过在搜索路径上创建一个类似的静态对象来操纵反应性闪亮对象。我知道我无法写入全局环境(它当前所做的),但我不确定如何在函数执行后让对象持续存在。

store_it <- function() {
  env <- new.env()
  assign("x", runif(10), env)
  assign("iris_df", head(iris), env)
  # View(env)
  env
}

# how I want to use it, doesn't work
store_it() # <environment: 0x0000012bd8959cb0>
x          # Error: object 'x' not found
iris_df    # Error: object 'iris_df' not found

# works
e <- attach(store_it())

x
iris_df

它做我想做的事,但我不喜欢它不断向搜索路径添加环境:

e <- attach(store_it())
# The following objects are masked from store_it() (pos = 3):
#   iris_df, x

e <- attach(store_it())
# The following objects are masked from store_it() (pos = 4):
#   iris_df, x

e <- attach(store_it())
# The following objects are masked from store_it() (pos = 5):
#   iris_df, x

这样做的正确方法是什么?我希望用户只写store_it()。如果attach() 是正确的方法,我该如何将它放在函数中,这样它就不会不断创造新的环境?请记住,解决方案需要通过 CRAN 的政策。提前致谢。

注意:有人可能会指出我过去曾问过类似的问题。我发了一个新帖子,因为这个问题更具体。 Package environment manipulation and submitting to CRAN

【问题讨论】:

    标签: r devtools cran


    【解决方案1】:

    1) CRAN 将允许您在 tempdir 中存储和读回项目,如下所示,或者可以省略 tmpdir 并像 R 的 Rprof 那样使用当前目录。

    store_it <- function() {
        iris_df <- head(iris)
        rand <- runif(3)
        save(list = ls(), file = file.path(tempdir(), "store.rda"))
    }
    
    retrieve_it <- function(envir = parent.frame()) {
        load(file.path(tempdir(), "store.rda"), envir = envir)
    }
    

    2) 如果包定义了保存对象的环境,也可以将对象存储在包本身中。这样就可以了。

    store <- new.env()
    
    store_it2 <- function() {
        store$iris_df <- head(iris)
        store$rand <- runif(3)
        invisible(store)
    }
    
    retrieve_it2 <- function(envir = parent.frame()) {
        list2env(as.list(store), envir)
    }
    

    retrieve_it2 的替代方法是在您的包中导出store,然后用户可以访问其内容,例如store$xwith(store, x) 以访问x,或者他们可以使用@987654330 附加它@。当然如果store被导出,那么两者都可以提供——用户可以直接访问store或者他们可以运行retrieve_it2()

    【讨论】:

    • 感谢您的建议。如果我理解正确,retrieve_it() 将写入全局环境并有机会覆盖现有对象。根据我从 CRAN 版主那里得到的反馈,我认为这是不允许的。
    • retrieve_it 将存储加载到由envir 参数指定的环境中,默认情况下是调用它的环境,但您可以指定任何您喜欢的环境。它所做的一切都很好。试着把它放在一个小包里然后运行R CMD check --as-cran,你会发现它不会报错。
    • 还添加了第二种方法。任何一种方法都应该有效。
    • 感谢您的帮助。理想情况下,这一切都发生在一个函数中。我在这里放了一个更好的代表。你能确认我是否正确使用它吗? gist.github.com/rjake/c709f0f699f5d4f037dfbb2eb7300783 我有一个 envir 参数,在函数中默认为 .GlobalEnv,但是当 CRAN 审查它时它没有通过。据我所知,R CMD Check 不够敏感,无法捕捉到问题,因为它专门寻找assign(..., .GlobalEnv),您能否进一步解释一下为什么parent.frame() 会比.GlobalEnv 更好?最终的结果似乎是一样的。再次感谢。
    • 我没有运行 RStudio,只是目测它看起来还不错。 envir = parent.frame() 是许多 R 函数使用的习语,看起来很灵活。用户可能不希望首先破坏他们的全局环境,这允许他们这样做或不这样做。我在答案末尾添加了更多讨论。
    【解决方案2】:

    一种方法:

    store_it <- local({
      .env <- NULL
      function() {
        if (is.null(.env)) .env <<- new.env(parent = emptyenv())
        .env$x <- runif(10)
        .env$iris_df <- head(iris)
        .env
      }
    })
    store_it()
    # <environment: 0x0000000049340d80>
    store_it()
    # <environment: 0x0000000049340d80>
    attach(store_it())
    x
    #  [1] 0.6478808 0.6862712 0.6969733 0.9513357 0.1560208 0.9332960 0.3966457
    #  [8] 0.5067889 0.4244998 0.3747476
    iris_df
    #   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    # 1          5.1         3.5          1.4         0.2  setosa
    # 2          4.9         3.0          1.4         0.2  setosa
    # 3          4.7         3.2          1.3         0.2  setosa
    # 4          4.6         3.1          1.5         0.2  setosa
    # 5          5.0         3.6          1.4         0.2  setosa
    # 6          5.4         3.9          1.7         0.4  setosa
    
    detach()
    x
    # Error: object 'x' not found
    # No traceback available 
    

    它仍然会多次将环境“附加”到您的搜索路径,因为通过反复调用attach,这就是您告诉它要做的事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-20
      • 1970-01-01
      • 1970-01-01
      • 2017-03-04
      • 1970-01-01
      • 2014-07-15
      • 1970-01-01
      • 2020-09-20
      相关资源
      最近更新 更多