我编写了一个函数来源包含其他函数脚本的文件,并将这些函数存储在另一个环境中,这样它们就不会使整个环境变得混乱。该代码有效,但包含三个eval(parse(...))
实例:
# sourceFunctionHidden ---------------------------
# source a function and hide the function from the global environment
sourceFunctionHidden <- function(functions, environment = "env", ...) {
if (environment %in% search()) {
while (environment %in% search()) {
if (!exists("counter", inherits = F)) counter <- 0
eval(parse(text = paste0("detach(", environment, ")")))
counter <- counter + 1
}
cat("detached", counter, environment, "s\n")
} else {cat("no", environment, "attached\n")}
if (!environment %in% ls(.GlobalEnv, all.names = T)) {
assign(environment, new.env(), pos = .GlobalEnv)
cat("created", environment, "\n")
} else {cat(environment, "already exists\n")}
sapply(functions, function(func) {
source(paste0("C:/Users/JT/R/Functions/", func, ".R"))
eval(parse(text = paste0(environment, "$", func," <- ", func)))
cat(func, "created in", environment, "\n")
})
eval(parse(text = paste0("attach(", environment, ")")))
cat("attached", environment, "\n\n")
}
关于eval(parse(...))
构造的次优性已经写了很多(参见here和here)。但是,我发现的讨论主要涉及子集化的替代策略。我的代码中的eval(parse(...))
的第一个和第三个实例不涉及子集化(第二个实例可能与子集化有关)。
有没有办法在不诉诸new.env(...)
的情况下调用[environment name]$[function name] <- [function name]
,attach(...)
和eval(parse(...))
?谢谢。
N.B。:我不想将我的功能名称更改为.name
以隐藏它们在全球环境中
为了它的价值,功能source
实际上使用eval(parse(...))
,虽然有点微妙的方式。首先,.Internal(parse(...))
用于创建表达式,后来经过更多处理后传递给eval
。因此,在这种情况下,eval(parse(...))
似乎对R核心团队来说已经足够了。
也就是说,您不需要跳过箍来将函数源化为新环境。 source
提供了一个可以用于此的local
论证。
local:TRUE,FALSE或环境,确定解析表达式的计算位置。
一个例子:
env = new.env()
source('test.r', local = env)
测试工作原理:
env$test('hello', 'world')
# [1] "hello world"
ls(pattern = 'test')
# character(0)
和一个示例test.r
文件使用此:
test = function(a,b) paste(a,b)
如果您想将其保持在global_env之外,请将其放入包中。 R社区中的人们常常将一堆常用的帮助函数放入他们自己的个人包中。
tl; dr:将引用的字符串转换为对象名称的正确方法是使用assign()
和get()
。见this post。
答案很长:@dww关于能够将source()
直接发送到特定环境的答案让我改变了eval(parse(...))
的第二个实例,如下所示:
# old version
source(paste0("C:/Users/JT/R/Functions/", func, ".R"))
eval(parse(text = paste0(environment, "$", func," <- ", func)))
# new version
source(
paste0("C:/Users/JT/R/Functions/", func, ".R"),
local = get(environment)
)
@dww的答案也让我去探索attach()
。 attach()
有一个参数,允许指定输出的环境。这导致我改变了eval(parse(...))
的第三个实例(下图)。请注意使用get()
将来自"env"
的environment
转换为env
所需的未引用的attach()
。
# old version
eval(parse(text = paste0("attach(", environment, ")")))
# new version
attach(get(environment), name = environment)
最后,在这个过程的某个时刻,我被提醒,rm()
有一个character.only
论点。 detach()
接受相同的参数,所以我更改了eval(parse())
的第二个实例如下:
# old version
eval(parse(text = paste0("detach(", environment, ")")))
# new version
detach(environment, character.only = T)
所以我的新代码是:
# sourceFunctionHidden ---------------------------
# source a function and hide the function from the global environment
sourceFunctionHidden <- function(functions, environment = "env", ...) {
if (environment %in% search()) {
while (environment %in% search()) {
if (!exists("counter", inherits = F)) counter <- 0
detach(environment, character.only = T)
counter <- counter + 1
}
cat("detached", counter, environment, "s\n")
} else {cat("no", environment, "attached\n")}
if (!environment %in% ls(.GlobalEnv, all.names = T)) {
assign(environment, new.env(), pos = .GlobalEnv)
cat("created", environment, "\n")
} else {cat(environment, "already exists\n")}
sapply(functions, function(func) {
source(
paste0("C:/Users/JT/R/Functions/", func, ".R"),
local = get(environment)
)
cat(func, "created in", environment, "\n")
})
attach(get(environment), name = environment)
cat("attached", environment, "\n\n")
}