【问题标题】:Value/reference equality for same named function in package/namespace environments?包/命名空间环境中相同命名函数的值/引用相等?
【发布时间】:2012-03-05 22:17:34
【问题描述】:

让我们抓取环境“namespace:stats”和“package:stats”

ns = getNamespace( "stats" )
pkg = as.environment( "package:stats" )

现在让我们在两者中获取函数“sd”:

nsSd = get( "sd" , envir = ns , inherits = FALSE )
pkgSd = get( "sd" , envir = pkg , inherits = FALSE )

它们是一样的吗?他们是!但“相同”是什么意思?引用或值相等?

identical( nsSd , pkgSd )

这意味着引用相等,因为以下返回 FALSE:

test1 = function() {}
test2 = function() {}
identical( test1 , test2 )

但如果这是真的,这意味着环境的框架可以在函数对象旁边包含函数指针。使问题进一步复杂化的事实是,一个函数可以“存在”在一个环境中,但可以告诉该函数它的执行环境是另一个环境。钱伯斯苏打水似乎没有答案(这是一本厚厚的书,也许我错过了!)

所以,我想要一个明确的答案。以下哪项是正确的?还是这里有假三分法?

  1. nsSdpkgSd 是两个不同的对象(尽管每个对象的副本 其他),其中pkgSd 中的对象具有ns 作为其执行 环境
  2. nsSdpkgSd 是指向同一个对象的指针。
  3. nsSd 是指向 pkgSd 的指针,因此它们被视为相同

【问题讨论】:

  • 可能值得看一下内部 identical 函数的 c 代码。 svn.r-project.org/R/trunk/src/main/identical.c
  • 它认为你让生活有点太复杂了。我们知道只有一个sd() 函数,因此您看到的任何差异都是由于您分别通过环境和命名空间的访问路径。
  • 根据 R 内部手册,函数的类型为 CLOSXP。匹配的指针算作相同,否则它会检查相同的 formalsbody 和任何 CLOENV(x) 是什么。
  • 你的第二个例子在检查身体时失败了。 identical(body(test1), body(test2))FALSE
  • 德克 - 你能详细说明一下吗?我不知道只有一个sd(),这就是为什么我发布=)看起来你在区分环境和命名空间,你是说包环境和命名空间环境吗?我想你是说答案是上面的 #2 还是 #3?

标签: r


【解决方案1】:

它们是指向同一个对象的指针。使用这个answer to another question,我们可以检查两个对象是否指向内存中的同一个地方。

are_same <- function(x, y)
{
  f <- function(x) capture.output(.Internal(inspect(x)))
  all(f(x) == f(y))
}

are_same(nsSd, pkgSd) #TRUE
are_same(1:5, 1:5)    #FALSE

【讨论】:

  • 我开始了一项赏金,我将奖励给你以表达我的感谢(当 24 等待期到期时)
  • 你太慷慨了。很高兴我能派上用场。
  • 非常酷的功能。直到现在,我都不知道当我执行j &lt;- rnorm(1e7); k &lt;- jjk 时,它们只是指向同一个内存位置的指针。但是当我做k[1] &lt;- 1 时,整个向量k 需要被复制到一个新位置,因为它现在不同了。所以k &lt;- jk[1] &lt;- 1 快得多。一个不错的服务 R 核心为我们提供了那里,我什至直到现在才欣赏它!
  • @JoshO'Brien:是的,尽管 R 假装总是按值传递事物,但为了获得更好的性能,它确实偷偷地只在可以逃脱的情况下传递对对象的引用。跨度>
  • 这是通过 promises 以与实现函数参数的惰性求值相同的方式实现的吗?
【解决方案2】:

这不是主要问题的答案。不过,在这个问题上,我同意 Dirk:只有一个 sd() 函数,并且可以根据情况通过不同的作用域路径访问它。例如,当您在命令行键入sd(x) 时,将通过其在package:stats 环境框架中的条目找到与名称sd 对应的函数。当您输入stats:::sd(x),或stats 包中的另一个函数调用sd(x) 时,将通过在namespace:stats 环境中的搜索找到它。


相反,我只是想说明您使用test1()test2() 的示例并没有真正暗示评估为identical 的对象的“引用相等”。要了解这两个不是identical 的真正原因,请查看str() 揭示的它们的结构:

test1 <- function() {}
test2 <- function() {}
identical( test1 , test2 )
# [1] FALSE

str(test1)
# function ()  
#  - attr(*, "srcref")=Class 'srcref'  atomic [1:8] 1 13 1 25 13 25 1 1
#   .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x01613f54> 

str(test2)
# function ()  
#  - attr(*, "srcref")=Class 'srcref'  atomic [1:8] 1 13 1 25 13 25 1 1
#   .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x01615730> 

如果您滚动到上面代码框的右侧,您会看到这两个函数的属性之一不同,即与它们的源文件关联的环境。 (我不太了解该属性,但这在这里并不真正相关。关键是它们不是identical!)

如果您告诉 R,您不想在创建的每个函数中保留 sourcefile 属性数据,identical(test1, test2) 的“意外”行为就会消失:

options(keep.source=FALSE)
test1 <- function() {}
test2 <- function() {}
identical( test1 , test2 )
# [1] TRUE

【讨论】:

  • 谢谢,乔希!这是一个有见地的帖子。我觉得钱伯斯在调用 re:sourcefile 属性 =)
  • @SFun28 - 很高兴在这里见到你。回复:钱伯斯的苏打水,“浓”是对这本书的一个很好的描述;令我惊讶的是,那里没有浪费页面。它确实回报了您为阅读它而付出的任何努力,我很感激。干杯。
  • 同意...它塞满了好东西。这篇文章代表了我在写一篇关于 R 如何搜索和查找内容的博客文章中的“缺失链接”。它是我从过去的帖子、钱伯斯和其他来源的发现的积累,并试图比search() 做得更深。我认为没有任何一个来源可以通过易于理解的视觉效果清楚地解释该过程。在我发布之前,我很想给你发一份预发稿以供批评。
  • 谢谢,乔希!我已经把你的电子邮件抄下来了。抱歉回复晚了,我不得不为情人节的东西奔波=)我希望你仍然可以删除评论,如果没有,对不起。我可能会在接下来的两三周内给你发一份草稿。
  • @SFun28 太好了。该评论已被删除,我期待您有机会处理它时看到草稿。
猜你喜欢
  • 2012-07-31
  • 1970-01-01
  • 1970-01-01
  • 2016-07-19
  • 2016-12-15
  • 1970-01-01
  • 2019-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多