包/命名空间环境中同一命名函数的值/引用相等性?

时间:2012-02-14 14:36:18

标签: r

让我们抓住环境“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 )

但如果这是真的,那就意味着Environment的框架可以包含函数指针和函数对象。使问题进一步复杂化的是,函数可以在一个环境中“生存”,但可以告诉函数其执行环境是另一个环境。钱伯斯SoDA似乎没有答案(它是一本密集的书,也许我错过了它!)

所以,我想要一个明确的答案。以下哪项是正确的?或者这里是否有错误的三分法?

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

2 个答案:

答案 0 :(得分:5)

它们是指向同一对象的指针。使用此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

答案 1 :(得分:4)

这主要不是你主要问题的答案。但是,在这个问题上,我同意Dirk:只有一个sd()函数,可以根据具体情况通过不同的范围路径访问它。例如,当您在命令行键入sd(x)时,将通过sd环境框架中的条目找到与名称package:stats对应的函数。当您输入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