[英]How can a non-imported method in a not-attached package be found by calls to functions not having it in their namespace?
An R namespace acts as the immediate environment for all functions in its associated package. R命名空间充当其关联包中所有函数的直接环境。 In other words, when function bar()
from package foo calls another function, the R evaluator first searches for the other function in <environment: namespace:foo>
, then in "imports.foo"
, <environment: namespace:base>
, <environment: R_GlobalEnv>
, and so on down the search list returned by typing search()
. 换句话说,当来自包foo的函数bar()
调用另一个函数时,R计算器首先在<environment: namespace:foo>
搜索另一个函数,然后在"imports.foo"
, <environment: namespace:base>
, <environment: R_GlobalEnv>
,依此类推,键入search()
返回的搜索列表。
One nice aspect of namespaces is that they can make packages act like better citizens: unexported functions in <environment: namespace:foo>
and functions in imports:foo
are available only: (a) to functions in foo ; 命名空间的一个很好的方面是它们可以使包充当更好的公民: <environment: namespace:foo>
未导出函数和imports:foo
函数imports:foo
仅可用:(a) foo中的函数; (b) to other packages that import from foo ; (b)从foo进口的其他包裹; or (c) via fully qualified function calls like foo:::bar()
. 或者(c)通过完全限定的函数调用,如foo:::bar()
。
Or so I thought until recently... 或者直到最近才想到......
This recent SO question highlighted a case in which a function well-hidden in its package's namespace was nonetheless found by a call to a seemingly unrelated function: 这个最近的SO问题突出了一个案例,其中通过调用看似无关的函数找到了一个隐藏在其包的名称空间中的函数:
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 answered the original question by pointing out that gmodels imports from the the package gdata , which includes a function reorder.factor
that gets dispatched to inside the second call to transform()
. @Andrie回答了原始问题,指出gmodels从包gdata导入,其中包含一个函数reorder.factor
,它被调度到第二次调用transform()
。 T1
differs from T2
because the first is calculated by stats:::reorder.default()
and the second by gdata:::reorder.factor()
. T1
与T2
不同,因为第一个是由stats:::reorder.default()
计算的,第二个是由gdata:::reorder.factor()
。
How is it that in the above call to transform(data, group=reorder(...))
, the dispatching mechanism for reorder
finds and then dispatches to gdata:::reorder.factor()
? 如何在上面的transform(data, group=reorder(...))
调用transform(data, group=reorder(...))
, reorder
的调度机制找到然后调度到gdata:::reorder.factor()
?
(An answer should include an explanation of the scoping rules that lead from a call involving functions in the stats and base packages to a seemingly well-hidden method in gdata .) (答案应该包括对范围规则的解释,这些规则从涉及统计数据和基础包中的函数的调用引导到gdata中看似隐藏得很好的方法。)
Neither gdata:::reorder.factor
, nor the gdata package as a whole are explicitly imported by gmodels . gdata:::reorder.factor
和gdata包都不是由gmodels显式导入的。 Here are the import*
directives in gmodels ' NAMESPACE file: 以下是gmodels的NAMESPACE文件中的import*
指令:
importFrom(MASS, ginv) importFrom(gdata, frameApply) importFrom(gdata, nobs)
There are no methods for reorder()
or transform()
in <environment: namespace:gmodels>
, nor in "imports:gmodels"
: 在<environment: namespace:gmodels>
中没有reorder()
或transform()
方法,也没有"imports:gmodels"
:
ls(getNamespace("gmodels")) ls(parent.env(getNamespace("gmodels")))
Detaching gmodels does not revert reorder()
's behavior: gdata:::reorder.factor()
still gets dispatched: 分离gmodels不会恢复reorder()
的行为: gdata:::reorder.factor()
仍然会被调度:
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: reorder.factor()
未存储在基本环境中的S3方法列表中:
grep("reorder", ls(.__S3MethodsTable__.)) # integer(0)
R chat threads from the last couple of days include some additional ideas. 过去几天的R聊天线程包括一些额外的想法。 Thanks to Andrie, Brian Diggs, and Gavin Simpson who (with others) should feel free to edit or add possibly impt. 感谢Andrie,Brian Diggs和Gavin Simpson(和其他人一起)应该随意编辑或添加可能的impt。 details to this question. 这个问题的细节。
I'm not sure if I correctly understand your question, but the main point is that group
is character vector while data$group
is factor. 我不确定我是否正确理解了你的问题,但重点是group
是字符向量而data$group
是因子。
After attaching gmodels
, the call for reorder(factor)
calls gdata:::reorder.factor
. 附加gmodels
, reorder(factor)
调用reorder(factor)
调用gdata:::reorder.factor
。 so, reorder(factor(group))
calls it. 所以, reorder(factor(group))
调用它。
In transform
, the function is evaluated within the environment of the first argument, so in T2 <- transform(data, group = reorder(group,-num))
, group
is factor. 在transform
,函数在第一个参数的环境中进行评估,因此在T2 <- transform(data, group = reorder(group,-num))
, group
是factor。
UPDATED 更新
library
attaches the import packages into loaded namespace. 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"
Just in case, the reorder
generic exists in namespace:stats
: 以防万一, reorder
泛型存在于namespace:stats
:
> r <- ls(.__S3MethodsTable__., envir = asNamespace("stats"))
> r[grep("reorder", r)]
[1] "reorder" "reorder.default" "reorder.dendrogram"
And for more details 并了解更多详情
The call of reorder
will search the S3generics in two envs: reorder
的调用将在两个环境中搜索S3generics:
see ?UseMethod
看?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). 首先在调用泛型函数的环境中,然后在定义泛型的环境的注册数据库中(通常是命名空间)。
then, loadNamespace
registers the S3 functions to the namespace. 然后, loadNamespace
将S3函数注册到命名空间。
So , in your case, library(gmodels)
-> loadNamespace(gdata)
-> registerS3Methods(gdata)
. 所以,在你的情况下, library(gmodels)
- > loadNamespace(gdata)
- > registerS3Methods(gdata)
。
After this, you can find it by: 在此之后,您可以通过以下方式找到它:
> methods(reorder)
[1] reorder.default* reorder.dendrogram* reorder.factor*
Non-visible functions are asterisked
However, as the reorder.factor
is not attached on your search path, you cannot access it directly: 但是,由于reorder.factor
未附加到您的搜索路径中,因此您无法直接访问它:
> reorder.factor
Error: object 'reorder.factor' not found
Probably this is whole scenario. 可能这是整个场景。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.