[英]R: attach all of the variables local to the function to global environment after it executes
[英]Is it possible to attach package environments as parents of a specific environment, not the global environment, in R?
我正在嘗試創建一個用 R 編寫的玩具 R REPL(這是源代碼)。 理想情況下,我希望 REPL 在 R 終端本身中運行,但既不干涉也不依賴任何已經在全球環境中評估過的東西。 不幸的是,我還沒有想出解決這個問題的辦法。 我面臨的主要挑戰之一是如何連接 package 環境。
根據Hadley 的 Advanced R , library()
和require()
附加的包成為全局環境的父母。 然而,這意味着如果我在我的玩具 REPL 中附加一個 package ,即使我沒有在全局環境中運行它,它也會成為全局環境的父級。
例如(請注意, R>
提示符是“正常”的 R 終端,而>>>>
是我的 REPL 的“終端”):
R> search()
# [1] ".GlobalEnv" "tools:rstudio" "package:stats"
# [4] "package:graphics" "package:grDevices" "package:utils"
# [7] "package:datasets" "package:methods" "Autoloads"
# [10] "package:base"
R> replr::replr(env = new.env()) # new.env() defaults to having global environment as a parent
>>>> library(gtfsio)
>>>> rlang::env_parents(last = emptyenv())
# [[1]] $ <env: global>
# [[2]] $ <env: package:gtfsio>
# [[3]] $ <env: tools:rstudio>
# [[4]] $ <env: package:stats>
# [[5]] $ <env: package:graphics>
# [[6]] $ <env: package:grDevices>
# [[7]] $ <env: package:utils>
# [[8]] $ <env: package:datasets>
# [[9]] $ <env: package:methods>
# [[10]] $ <env: Autoloads>
# [[11]] $ <env: package:base>
# [[12]] $ <env: empty>
>>>> import_gtfs()
# Error: argument "path" is missing, with no default
>>>> q()
R> search()
# [1] ".GlobalEnv" "package:gtfsio" "tools:rstudio"
# [4] "package:stats" "package:graphics" "package:grDevices"
# [7] "package:utils" "package:datasets" "package:methods"
# [10] "Autoloads" "package:base"
我們可以看到我可以使用gtfsio
' import_gtfs()
function ( path
丟失,但你明白了),但 package 也連接到“主” ZE1E1D603D405C731827 終端。 如果我嘗試使用另一個環境作為新環境的父環境,我什至無法訪問包的功能,因為它無法找到它們,因為 package 環境成為全局環境的父環境,而不是我的新環境:
Restarting R session...
R> search()
# [1] ".GlobalEnv" "tools:rstudio" "package:stats"
# [4] "package:graphics" "package:grDevices" "package:utils"
# [7] "package:datasets" "package:methods" "Autoloads"
# [10] "package:base"
R> replr::replr(env = new.env(parent = baseenv()))
>>>> library(gtfsio)
>>>> rlang::env_parents()
# [[1]] $ <env: package:base>
# [[2]] $ <env: empty>
>>>> import_gtfs()
# Error: could not find function "import_gtfs"
>>>> q()
R> search()
# [1] ".GlobalEnv" "package:gtfsio" "tools:rstudio"
# [4] "package:stats" "package:graphics" "package:grDevices"
# [7] "package:utils" "package:datasets" "package:methods"
# [10] "Autoloads" "package:base"
那么,有沒有辦法將 package 環境附加為自定義環境的父級,而不是全局環境? 如果沒有,有沒有辦法解決這個問題?
干杯!
編輯:
抱歉,我應該詳細說明 REPL 的工作原理。
基本上,我只是使用readline()
讀取用戶輸入,將其解析為表達式並在指定環境中對其進行評估。 下面的代碼應該適用於一個簡單的演示:
simple_repl <- function(env = new.env()) {
while (TRUE) {
input <- readline(">>>> ")
if (input == "q()") break
expr <- parse(text = input)
result <- withVisible(
eval(expr, envir = env)
)
if (result$visible)
print(result$value)
}
}
我上面鏈接到我的 GitHub 的代碼在處理某些條件時有點復雜,但這仍然是基本思想。
然后, library()
調用將被評估為eval(expression(library(gtfsio)), envir = env)
。
您只有一個搜索路徑,因此無法正確附加到另一個搜索路徑。
您仍然可以擁有父環境鏈,我們可能會在您的repl_env
中重新定義library
以設置此鏈
repl_env <- new.env()
with(repl_env, library <- function(package) {
# fetch repl_env from the inside
repl_env <- parent.env(environment())
# and its parent (.GlobalEnv the first time)
parent_env <- parent.env(repl_env)
# create a new env for our package and fill it
pkg_env <- new.env()
package <- deparse1(substitute(package))
object_nms <- getNamespaceExports(package)
objects <- mget(object_nms, envir = asNamespace(package))
list2env(objects, pkg_env)
# stitch it above repl_env and below repl_env's parent
parent.env(pkg_env) <- parent_env
parent.env(repl_env) <- pkg_env
# base::library returns the search path invisibly but here it woudn't make
# sense so we just return NULL
invisible(NULL)
})
simple_repl(repl_env)
>>>> x <- "hello"
>>>> y <- "world"
>>>> library(glue)
>>>> glue("{x} {y}")
#> hello world
>>>>
# the {glue} package is not on the search path
search()
#> [1] ".GlobalEnv" "tools:rstudio" "package:stats" "package:graphics"
#> [5] "package:grDevices" "package:utils" "package:datasets" "package:methods"
#> [9] "Autoloads" "package:base"
如果您不想訪問全局環境的對象,請使用repl_env <- new.env(parent = parent.env(.GlobalEnv))
作為第一行。
然而,它永遠不會 100% 健壯,這是一個有趣的練習,但在認真對待它之前要仔細考慮。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.