R 命名空间充当其关联包中所有函数的直接环境。换句话说,当包 foo 中的函数 bar()
调用另一个函数时,R evaluator 首先在 <environment: namespace:foo>
中搜索另一个函数,然后在 "imports.foo"
、 <environment: namespace:base>
、 <environment: R_GlobalEnv>
等通过键入 search()
返回的搜索列表向下搜索。
命名空间的一个很好的方面是它们可以使包表现得像更好的公民:<environment: namespace:foo>
中未导出的函数和 imports:foo
中的函数仅可用: (a) foo 中的函数; (b) 从 foo 导入的其他包;或 (c) 通过完全限定的函数调用,如 foo:::bar()
。
或者直到最近我还以为...
行为
This recent SO question 强调了一个案例,在该案例中,一个隐藏在其包命名空间中的函数仍然通过调用看似无关的函数而被发现:
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
,该函数被分派(dispatch)到对 transform()
的第二次调用。 T1
与 T2
不同,因为第一个由 stats:::reorder.default()
计算,第二个由 gdata:::reorder.factor()
计算。我的问题
在上面对
transform(data, group=reorder(...))
的调用中, reorder
的调度机制如何找到然后调度到 gdata:::reorder.factor()
?(答案应包括对涉及 stats 和 基础 包中的函数的调用到 gdata 中看似隐藏良好的方法的调用的范围规则的解释。)
更多可能有用的细节
gdata:::reorder.factor
和 gdata 包作为一个整体都不是由 gmodels 显式导入的。以下是 gmodels ' NAMESPACE 文件中的 import*
指令:importFrom(MASS, ginv)
importFrom(gdata, frameApply)
importFrom(gdata, nobs)
reorder()
和 transform()
中没有 <environment: namespace:gmodels>
或 "imports:gmodels"
的方法:ls(getNamespace("gmodels"))
ls(parent.env(getNamespace("gmodels")))
reorder()
的行为: gdata:::reorder.factor()
仍然被调度:detach("package:gmodels")
T3 <- transform(data, group=reorder(group,-num))
identical(T3, T2)
# [1] TRUE
reorder.factor()
未存储在基础环境中的 S3 方法列表中:grep("reorder", ls(.__S3MethodsTable__.))
# integer(0)
最近几天的 R 聊天线程包括一些额外的想法。感谢 Andrie、Brian Diggs 和 Gavin Simpson,他们(与其他人)应该可以随意编辑或添加可能的 impt。这个问题的详细信息。
最佳答案
我不确定我是否正确理解了您的问题,但要点是 group
是字符向量,而 data$group
是因子。
附加 gmodels
后,对 reorder(factor)
的调用调用 gdata:::reorder.factor
。
所以,reorder(factor(group))
调用它。
在 transform
中,函数在第一个参数的环境中进行评估,因此在 T2 <- transform(data, group = reorder(group,-num))
中,group
是因子。
更新 library
将导入包附加到加载的命名空间。
> loadedNamespaces()
[1] "RCurl" "base" "datasets" "devtools" "grDevices" "graphics" "methods"
[8] "stats" "tools" "utils"
> library(gmodels) # here, namespace:gdata is loaded
> loadedNamespaces()
[1] "MASS" "RCurl" "base" "datasets" "devtools" "gdata" "gmodels"
[8] "grDevices" "graphics" "gtools" "methods" "stats" "tools" "utils"
以防万一,
reorder
泛型存在于 namespace:stats
中:> r <- ls(.__S3MethodsTable__., envir = asNamespace("stats"))
> r[grep("reorder", r)]
[1] "reorder" "reorder.default" "reorder.dendrogram"
更多细节
调用
reorder
将在两个环境中搜索 S3generics:见
?UseMethod
first in the environment in which the generic function is called, and then in the registration data base for the environment in which the generic is defined (typically a namespace).
然后,
loadNamespace
将 S3 函数注册到命名空间。所以,在你的情况下,
library(gmodels)
-> loadNamespace(gdata)
-> registerS3Methods(gdata)
。在此之后,您可以通过以下方式找到它:
> methods(reorder)
[1] reorder.default* reorder.dendrogram* reorder.factor*
Non-visible functions are asterisked
但是,由于
reorder.factor
未附加在您的搜索路径中,因此您无法直接访问它:> reorder.factor
Error: object 'reorder.factor' not found
可能这就是整个场景。
关于r - 如何通过调用在其命名空间中没有它的函数来找到未附加包中的非导入方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11004018/