Zhe*_*lei 24 r function environment-variables with-statement assign
更新2 @G.格洛腾迪克发布了两种方法.第二个是改变函数内的函数环境.这解决了我的编码重复过多的问题.在将脚本编写成包时,我不确定这是否是通过CRAN检查的好方法.当我得出一些结论时,我会再次更新.
更新
我试图传递很多输入参数变量,f2并且不想索引函数内的每个变量env$c, env$d, env$calls,这就是我尝试使用within f5和f6(修改过f2)的原因.但是,assign不能在with里面工作{},移动assign到外面with会做的工作,但在我的实际情况下,我有几个assigns在with表达式内,我不知道如何with轻松地将它们移出功能.
这是一个例子:
## 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()
Run Code Online (Sandbox Code Playgroud)
函数f2在内部f1,在f2调用时,它calls,c,d在环境中查找变量environment(f1).这就是我想要的.
但是,当我想f2在其他函数中使用时,我将在Global环境中定义此函数,而不是调用它f4.
f4 <- function(P){
assign("calls", calls+1, inherits=TRUE)
print(calls)
return(P+c+d)
}
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为它将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()
Run Code Online (Sandbox Code Playgroud)
应该calls,c,d在输入参数中定义安全方式f4,然后将这些参数传递给f4.但是,在我的情况下,有太多的变量要传递给这个函数f4,最好我可以将它作为一个环境传递并告诉f4不要查看Global环境(environment(f4)),只看看调用environmentwhen时f3.
我现在解决它的方法是将环境用作列表并使用该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()
Run Code Online (Sandbox Code Playgroud)
但是,现在assign("calls", calls+1, inherits=TRUE)不能正常工作,因为assign不会修改原始对象.变量calls连接到目标函数所在的优化函数f5.这就是我使用assign而不是calls作为输入参数传递的原因.使用attach对我来说也不清楚.这是我纠正assign问题的方法:
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()
Run Code Online (Sandbox Code Playgroud)
我不确定如何在R中做到这一点.我正朝着正确的方向前进,特别是在通过CRAN检查时?有人对此有一些暗示吗?
G. *_*eck 25
(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()
Run Code Online (Sandbox Code Playgroud)
(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()
Run Code Online (Sandbox Code Playgroud)
(3)宏使用eval.parent(替换(...)) 另一种方法是定义一个类似宏的构造,它有效地注入f2c内联体f1c1.除了线(不需要)和整个身体的包裹之外,这里f2c是相同的. 除了调用替换为调用之外,它是相同的. f2bcalls <- calls + 1<<-eval.parent(substitute({...}))f1cf1af2af2c
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()
Run Code Online (Sandbox Code Playgroud)
(4)defmacro 这几乎与上一个解决方案相同,只是它defmacro在gtools包中用来定义宏而不是自己做.(另请参阅另一个defmacro版本的Rcmdr包.)由于工作方式defmacro我们也必须通过,calls但由于它是一个宏而不是一个函数,这只是告诉它替换calls,并且与传递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()
Run Code Online (Sandbox Code Playgroud)