命名空间的一个好处是它们可以使包表现得更像良好的公民:在中未导出的函数和在imports:foo中的函数仅对foo的函数、从foo导入的其他包或通过完全限定函数调用(如foo:::bar())可用。
或者我最近这样认为...
行为
最近的一个Stack Overflow问题突出了这样一种情况,即一个在其包命名空间中很好隐藏的函数却被一个看似无关的函数调用找到:
group <- c("C","F","D","B","A","E")
num <- c(12,11,7,7,2,1)
data <- data.frame(group,num)
## Evaluated **before** attaching 'gmodels' package
T1 <- transform(data, group = reorder(group,-num))
## Evaluated **after** attaching 'gmodels
library(gmodels)
T2 <- transform(data, group = reorder(group,-num))
identical(T1, T2)
# [1] FALSE
它的直接原因
@Andrie通过指出gmodels从包gdata中导入,该包包括一个函数reorder.factor
,该函数在第二次调用transform()
内部被调度。 T1
与T2
的区别在于第一个是由stats:::reorder.default()
计算的,而第二个是由gdata:::reorder.factor()
计算的。
我的问题
在上面对transform(data, group=reorder(...))
的调用中,reorder
的调度机制如何找到并调度到gdata:::reorder.factor()
?
(答案应包括解释从涉及stats和base包中的函数的调用到看似隐藏的gdata方法的作用域规则。)
更多可能有帮助的细节
Neither
gdata:::reorder.factor
, nor the gdata package as a whole are explicitly imported by gmodels. Here are theimport*
directives in gmodels' NAMESPACE file:importFrom(MASS, ginv) importFrom(gdata, frameApply) importFrom(gdata, nobs)
There are no methods for
reorder()
ortransform()
in<environment: namespace:gmodels>
, nor in"imports:gmodels"
:ls(getNamespace("gmodels")) ls(parent.env(getNamespace("gmodels")))
Detaching gmodels does not revert
reorder()
's behavior:gdata:::reorder.factor()
still gets dispatched:detach("package:gmodels") T3 <- transform(data, group=reorder(group,-num)) identical(T3, T2) # [1] TRUE
reorder.factor()
is not stored in the list of S3 methods in the base environment:grep("reorder", ls(.__S3MethodsTable__.)) # integer(0)
最近几天的R聊天记录中包含了一些额外的想法。感谢Andrie、Brian Diggs和Gavin Simpson(与其他人一起)可以自由编辑或添加可能重要的细节到这个问题中。