r - 在R中,如何使函数内的变量可供该函数内的较低级别函数使用?(with、attach、environment)

标签 r function environment-variables with-statement assign

更新2 @G。格洛腾迪克发布了两种方法。第二个是改变函数内部的函数环境。这解决了我的编码重复过多的问题。我不确定这是否是在将脚本打包成包时通过 CRAN 检查的好方法。当我有一些结论时,我会再次更新。

更新

我试图将大量输入参数变量传递给f2,并且不想将函数内的每个变量索引为env$c、env$d、env$calls,这就是为什么我尝试在 f5f6(修改后的 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 。这里f2cf2b 相同除了calls <- calls + 1线(不需要<<-)并将整个 body 包裹在eval.parent(substitute({...}))中。 f1cf1a 相同除了调用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/

相关文章:

javascript - 重置rhandsontable中的选定范围

在 R 的 Shiny 侧边栏中删除粗体

regex - 在 R 中使用正则表达式捕获部分字符串

syntax - F#:为什么我必须为不带参数的函数显式指定 'unit'?

javascript - 未捕获的类型错误 : undefined is not a function jquery

r - 将数据导出到 Excel 工作表中的特定单元格

r - 在具有构面和多个几何图形的函数中使用 ggplot

python - 错误系统调用spawn C :\Windows\system32\cmd. exe

php - 在 PHP 5.2.x 中使用 Docker 环境变量

scala - 为 NetBeans 设置 Scala - 错误