save(),意外行为

Posted

技术标签:

【中文标题】save(),意外行为【英文标题】:save(), unexpected behavior 【发布时间】:2014-07-22 17:12:18 【问题描述】:

我正在尝试通过 save() 保存函数调用中的变量

f <- function(x) 
  r <- x - g(x)
  r

g <- function(y) 
  r <- y * h(y)
  r

h <- function(z) 
  save(list = ls(all = TRUE), file = "hello.RData", envir = parent.frame())
  r <- log(z)
  if (r < 10)
    r^2
  else r^3

然而,这会返回错误“object z not found”,即使根据文档 parent.frame() 是 envir 的标准值。

save(list = ls(all = TRUE), file = "hello.RData", envir = sys.frame())

也不行

save(list = ls(all = TRUE), file = "hello.RData")

这行得通。但是,如果不是文档中给出的标准值,envir 实际上是什么对我来说有点神秘。

错误的原因是什么,为什么父框架是要在save()中查看的标准环境?

【问题讨论】:

虽然我知道这里正在进行范围界定,但您的函数 h 在返回正确值的意义上工作得很好。您应该明确指出,将内部变量保存到您的 .rdata 文件是行不通的。 【参考方案1】:

需要注意的重要一点是,函数的默认值在哪里评估和你传入的值在哪里评估是不同的。考虑

ff<-function(a, b=a+2) print(b)

ff(2);
# [1] 4
ff(2, a+2);
# Error in print(b) : object 'a' not found

尽管b 的“默认”是a+2,但我们不能只传入a+2,因为它需要在不同的上下文中进行评估。

这是另一个例子

gg<-function(a) 
    ff(2, match.call());


ff<-function(a, b=match.call()) 
    print(b)


ff(2);
# ff(a = 2)
gg(2)
# gg(a = 2);

尽管gg 将相同的“默认值”传递给ff,但我们得到了不同的行为。

save(..., envir=parent.frame()) 就是这样。当您在h() 中调用该函数时,您将从调用h() 的位置获取帧,但如果您未指定环境,当save 调用parent.frame() 时,save 将获得调用的帧save() 被调用。如果你想明确地将 current 环境传递给save(),你可以这样做

save(list = ls(all = TRUE), file = "hello.RData", envir=environment())

但这与根本不指定envir= 参数的作用基本相同。

所以文档是正确的,只是行为会有所不同,具体取决于实际调用parent.frame()的人。

【讨论】:

正如 R-inferno 中所讨论的。【参考方案2】:

这个问题与范围界定有关。有关范围的深入描述,请查看这篇文章http://adv-r.had.co.nz/Functions.html#lexical-scoping

首先,通过指定 envir=parent.frame() 来选择全局环境。这是因为您的函数未在另一个函数或对象中定义。例如,查看我在下面定义的两个不同 h 函数中打印 parent.frame 之间的区别。

!> h <- function(z)
 +     print(parent.frame())
 + 
 >
 >
 > h(10)
 <environment: R_GlobalEnv>
 >
 > h <- function(z)
 +     b <- function()
 +         print(parent.frame())
 +     b()
 + 
 >
 > h()
 <environment: 0x10f06b3c0>

我相信你要么想将你的函数相互嵌套(如上所示的函数 h 和 b),要么声明一个“全局变量”。这是由

<<-

命令

例如:

 > h <- function(z) 
 +         r <<- log(z)
 +         if (r < 10)
 +                 r <<- r^2
 +         else r<<- r^3
 +     
 > h(1)
 > r
 [1] 0
 > h(10)
 > r
 [1] 5.301898
 > h(10000)
!> r
 [1] 84.83037

【讨论】:

以上是关于save(),意外行为的主要内容,如果未能解决你的问题,请参考以下文章

指针的意外行为(操作时)但使用双指针时定义的行为

Swift中的嵌套函数意外行为?

UIlabel 大小以适应意外行为

连接字符串的意外行为

NSFetchRequest 的意外行为

使用 FieldOffset 意外行为的结构