首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从.GlobalEnv分离脚本:源脚本的源脚本

从.GlobalEnv分离脚本:源脚本的源脚本
EN

Stack Overflow用户
提问于 2021-09-23 12:49:12
回答 4查看 215关注 0票数 3

这个问题类似于Source script to separate environment in R, not the global environment,但有一个关键的转折。

考虑另一个脚本的来源:

代码语言:javascript
复制
# main.R
source("funs.R")
x <- 1
代码语言:javascript
复制
# funs.R
hello <- function() {message("Hi")}

我希望获得脚本main.R,并将所有内容保存在“本地”环境中,env <- new.env()说。通常,人们可以调用source("main.R", local = env),并期望一切都在env环境中。但是,这里不是这样的:x env**,的一部分,但是函数** hello 不是!它在.GlobalEnv**.**

问题:我如何在R中将脚本源到单独的环境中,即使该脚本本身来源于其他脚本,而又不修改其他脚本的来源呢?

谢谢你的帮助,如果我能澄清什么,请告诉我。

编辑1:更新的问题是明确的,脚本作为源不能被修改(假设它们不在你的控制之下)。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2021-10-02 14:52:48

您可以使用trace在函数中注入代码,这样就可以强制所有source调用设置local = TRUE。在这里,如果localFALSE,那么我就重写它,以防任何对source的嵌套调用都会因为它们自己的特殊逻辑而将其设置为其他环境。

代码语言:javascript
复制
env <- new.env()

# use !isTRUE if you want to support older R versions (<3.5.0)
tracer <- quote(
  if (isFALSE(local)) {
    local <- TRUE
  }
)

trace(source, tracer, print = FALSE, where = .GlobalEnv)

# if you're doing this inside a function, uncomment the next line
#on.exit(untrace(source, where = .GlobalEnv))

source("main.R", local = env)

正如代码中提到的,如果将此逻辑封装在函数中,请考虑使用on.exit确保即使存在错误,也要确保untrace

编辑:正如注释中提到的,如果您将要加载的一些脚本假设存在1(全局)环境,则可能会出现问题。我想你可以把追踪器改成

代码语言:javascript
复制
tracer <- quote(
  if (missing(local)) {
    local <- TRUE
  }
)

或者也许

代码语言:javascript
复制
tracer <- quote(
  if (isFALSE(local)) {
    # fetch the specific environment you created
    local <- get("env", .GlobalEnv)
  }
)

前者假设,如果脚本根本没有指定local,那么它不关心哪个环境会保存所有内容。后者假设没有指定local或将其设置为FALSElocal调用希望一切都在1环境中结束,并修改逻辑以使用您的环境而不是全局环境。

票数 2
EN

Stack Overflow用户

发布于 2021-10-04 10:05:27

免责声明:非常丑陋和潜在的危险,但无论如何。

重新定义source

代码语言:javascript
复制
env<-new.env()
source<-function(...) base::source(..., local = env)
source("main.R")
#just remove your redefinition when you don't need it
rm(source)
票数 1
EN

Stack Overflow用户

发布于 2021-10-06 13:17:05

保护自己不受无法控制的代码副作用影响的最佳方法是隔离。您可以使用callr轻松地执行单独R会话中隔离的脚本:

使用环境:

代码语言:javascript
复制
env <- new.env()
env <- as.environment(callr::r(function(env) {
    list2env(env, .GlobalEnv)
    source("main.R")
    as.list(.GlobalEnv)
}, args = list(as.list(env))))
env
#> <environment: 0x0000000018124878>
env$hello()
#> Hi

更简单的版本粘在列表上:

代码语言:javascript
复制
params <- list()
results <- callr::r(function(params) {
    list2env(params, .GlobalEnv)
    source("main.R")
    as.list(.GlobalEnv)
}, args = list(params))
results
#> $x
#> [1] 1
#> 
#> $hello
#> function () 
#> {
#>   message("Hi")
#> }
results$hello()
#> Hi

只有当您实际需要提供脚本输入(不用于示例)时,才需要param部件。显然,这将不适用于开放连接和类似的东西。在这种情况下,您可能需要查看callr::r_session

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69300358

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档