这个问题类似于Source script to separate environment in R, not the global environment,但有一个关键的转折。
考虑另一个脚本的来源:
# main.R
source("funs.R")
x <- 1# funs.R
hello <- function() {message("Hi")}我希望获得脚本main.R,并将所有内容保存在“本地”环境中,env <- new.env()说。通常,人们可以调用source("main.R", local = env),并期望一切都在env环境中。但是,这里不是这样的:x 是 env**,的一部分,但是函数** hello 不是!它在.GlobalEnv**.** 里
问题:我如何在R中将脚本源到单独的环境中,即使该脚本本身来源于其他脚本,而又不修改其他脚本的来源呢?
谢谢你的帮助,如果我能澄清什么,请告诉我。
编辑1:更新的问题是明确的,脚本作为源不能被修改(假设它们不在你的控制之下)。
发布于 2021-10-02 14:52:48
您可以使用trace在函数中注入代码,这样就可以强制所有source调用设置local = TRUE。在这里,如果local是FALSE,那么我就重写它,以防任何对source的嵌套调用都会因为它们自己的特殊逻辑而将其设置为其他环境。
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(全局)环境,则可能会出现问题。我想你可以把追踪器改成
tracer <- quote(
if (missing(local)) {
local <- TRUE
}
)或者也许
tracer <- quote(
if (isFALSE(local)) {
# fetch the specific environment you created
local <- get("env", .GlobalEnv)
}
)前者假设,如果脚本根本没有指定local,那么它不关心哪个环境会保存所有内容。后者假设没有指定local或将其设置为FALSE的local调用希望一切都在1环境中结束,并修改逻辑以使用您的环境而不是全局环境。
发布于 2021-10-04 10:05:27
免责声明:非常丑陋和潜在的危险,但无论如何。
重新定义source
env<-new.env()
source<-function(...) base::source(..., local = env)
source("main.R")
#just remove your redefinition when you don't need it
rm(source)发布于 2021-10-06 13:17:05
保护自己不受无法控制的代码副作用影响的最佳方法是隔离。您可以使用callr轻松地执行单独R会话中隔离的脚本:
使用环境:
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更简单的版本粘在列表上:
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。
https://stackoverflow.com/questions/69300358
复制相似问题