更新2 @G。格洛腾迪克发布了两种方法。第二个是改变函数内部的函数环境。这解决了我的编码重复过多的问题。我不确定这是否是在将脚本打包成包时通过 CRAN 检查的好方法。当我有一些结论时,我会再次更新。
更新
我试图将大量输入参数变量传递给f2
,并且不想将函数内的每个变量索引为env$c、env$d、env$calls
,这就是为什么我尝试在 f5
和 f6
(修改后的 f2
)中使用 with
。但是,assign
无法与 {}
内的 with
配合使用,请将 assign
移至 with
外部code> 会完成这项工作,但在我的实际情况中,我在 with
表达式中有一些 assign
,我不知道如何将它们移出 轻松使用
功能。
这是一个例子:
## In the <environment: R_GlobalEnv>
a <- 1
b <- 2
f1 <- function(){
c <- 3
d <- 4
f2 <- function(P){
assign("calls", calls+1, inherits=TRUE)
print(calls)
return(P+c+d)
}
calls <- 0
v <- vector()
for(i in 1:10){
v[i] <- f2(P=0)
c <- c+1
d <- d+1
}
return(v)
}
f1()
函数f2
位于f1
内部,当f2
被调用时,它会查找变量calls,c,d
在环境 environment(f1)
中。这就是我想要的。
但是,当我想在其他函数中也使用 f2
时,我会在全局环境中定义此函数,并将其称为 f4
。
f4 <- function(P){
assign("calls", calls+1, inherits=TRUE)
print(calls)
return(P+c+d)
}
这不起作用,因为它将在全局环境中查找 calls,c,d
而不是在调用该函数的函数内部。例如:
f3 <- function(){
c <- 3
d <- 4
calls <- 0
v <- vector()
for(i in 1:10){
v[i] <- f4(P=0) ## or replace here with f5(P=0)
c <- c+1
d <- d+1
}
return(v)
}
f3()
安全的方法应该是在f4
的输入参数中定义calls,c,d
,然后将这些参数传递给f4
。但是,就我而言,有太多变量需要传递到此函数 f4
中,最好我可以将其作为环境传递并告诉 f4
不要查看全局环境(environment(f4)
),仅在调用f3
时查看environment
内部。
我现在解决的方法是将环境作为列表,使用with
函数。
f5 <- function(P,liste){
with(liste,{
assign("calls", calls+1, inherits=TRUE)
print(calls)
return(P+c+d)
}
)
}
f3 <- function(){
c <- 3
d <- 4
calls <- 0
v <- vector()
for(i in 1:10){
v[i] <- f5(P=0,as.list(environment())) ## or replace here with f5(P=0)
c <- c+1
d <- d+1
}
return(v)
}
f3()
但是,现在 assign("calls", Calls+1,继承=TRUE)
无法正常工作,因为 assign
不会修改原始对象。变量calls
连接到目标函数为f5
的优化函数。这就是我使用 assign
而不是传递 calls
作为输入参数的原因。我也不清楚使用 attach
。这是我纠正分配
问题的方法:
f7 <- function(P,calls,liste){
##calls <<- calls+1
##browser()
assign("calls", calls+1, inherits=TRUE,envir = sys.frame(-1))
print(calls)
with(liste,{
print(paste('with the listed envrionment, calls=',calls))
return(P+c+d)
}
)
}
########
##################
f8 <- function(){
c <- 3
d <- 4
calls <- 0
v <- vector()
for(i in 1:10){
##browser()
##v[i] <- f4(P=0) ## or replace here with f5(P=0)
v[i] <- f7(P=0,calls,liste=as.list(environment()))
c <- c+1
d <- d+1
}
f7(P=0,calls,liste=as.list(environment()))
print(paste('final call number',calls))
return(v)
}
f8()
我不确定在 R 中应该如何完成此操作。我的方向正确吗,尤其是在通过 CRAN 检查时?有人对此有一些提示吗?
最佳答案
(1) 传递调用者的环境。 您可以显式传递父环境和索引到其中。试试这个:
f2a <- function(P, env = parent.frame()) {
env$calls <- env$calls + 1
print(env$calls)
return(P + env$c + env$d)
}
a <- 1
b <- 2
# same as f1 except f2 removed and call to f2 replaced with call to f2a
f1a <- function(){
c <- 3
d <- 4
calls <- 0
v <- vector()
for(i in 1:10){
v[i] <- f2a(P=0)
c <- c+1
d <- d+1
}
return(v)
}
f1a()
(2)重置被调用函数的环境我们可以重置f2b
的环境。在f1b
如下所示:
f2b <- function(P) {
calls <<- calls + 1
print(calls)
return(P + c + d)
}
a <- 1
b <- 2
# same as f1 except f2 removed, call to f2 replaced with call to f2b
# and line marked ## at the beginning is new
f1b <- function(){
environment(f2b) <- environment() ##
c <- 3
d <- 4
calls <- 0
v <- vector()
for(i in 1:10){
v[i] <- f2b(P=0)
c <- c+1
d <- d+1
}
return(v)
}
f1b()
(3) 使用 eval.parent(substitute(...)) 的宏 另一种方法是定义一个类似宏的构造,它有效地注入(inject) f2c
的主体。内联到 f1c1
。这里f2c
与 f2b
相同除了calls <- calls + 1
线(不需要<<-
)并将整个 body 包裹在eval.parent(substitute({...}))
中。 f1c
与 f1a
相同除了调用f2a
替换为对 f2c
的调用。
f2c <- function(P) eval.parent(substitute({
calls <- calls + 1
print(calls)
return(P + c + d)
}))
a <- 1
b <- 2
f1c <- function(){
c <- 3
d <- 4
calls <- 0
v <- vector()
for(i in 1:10){
v[i] <- f2c(P=0)
c <- c+1
d <- d+1
}
return(v)
}
f1c()
(4) defmacro 这与上一个解决方案几乎相同,只是它使用 defmacro
在 gtools 包中定义宏而不是我们自己做。 (另请参阅 Rcmdr 包以获取另一个 defmacro 版本。)因为方式 defmacro
作品我们还必须通过calls
但由于它是一个宏而不是一个函数,这只是告诉它替换 calls
in and 与传递 calls
不同到一个函数。
library(gtools)
f2d <- defmacro(P, calls, expr = {
calls <- calls + 1
print(calls)
return(P + c + d)
})
a <- 1
b <- 2
f1d <- function(){
c <- 3
d <- 4
calls <- 0
v <- vector()
for(i in 1:10){
v[i] <- f2d(P=0, calls)
c <- c+1
d <- d+1
}
return(v)
}
f1d()
关于r - 在R中,如何使函数内的变量可供该函数内的较低级别函数使用?(with、attach、environment),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14399205/