30

R 命名空间充当其关联包中所有函数的直接环境。换句话说,当foobar()包中的函数调用另一个函数时,R 求值器首先在 中搜索另一个函数,然后在键入返回的搜索列表中搜索、、等等。<environment: namespace:foo>"imports.foo"<environment: namespace:base><environment: R_GlobalEnv>search()

命名空间的一个很好的方面是它们可以使包表现得像更好的公民:未导出的函数 in<environment: namespace:foo>和函数 inimports:foo仅可用: (a) 对foo中的函数;(b) 从foo导入的其他包;或 (c) 通过完全限定的函数调用,如foo:::bar().

或者直到最近我还以为...

行为

这个最近的 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在第二次调用transform(). T1不同,T2因为第一个由 计算,stats:::reorder.default()第二个由计算gdata:::reorder.factor()

我的问题

在上面的调用中transform(data, group=reorder(...)),调度机制是如何reorder找到然后调度到的gdata:::reorder.factor()

(答案应包括对范围规则的解释,这些规则从涉及stats基本包中的函数的调用到gdata中看似隐藏良好的方法。)


更多可能有用的细节

  1. Neither gdata:::reorder.factor, nor the gdata package as a whole are explicitly imported by gmodels. Here are the import* directives in gmodels' NAMESPACE file:

    importFrom(MASS, ginv)
    importFrom(gdata, frameApply)
    importFrom(gdata, nobs)
    
  2. There are no methods for reorder() or transform() in <environment: namespace:gmodels>, nor in "imports:gmodels":

    ls(getNamespace("gmodels"))
    ls(parent.env(getNamespace("gmodels")))
    
  3. 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
    
  4. reorder.factor() is not stored in the list of S3 methods in the base environment:

    grep("reorder", ls(.__S3MethodsTable__.))
    # integer(0)
    

R chat threads from the last couple of days include some additional ideas. Thanks to Andrie, Brian Diggs, and Gavin Simpson who (with others) should feel free to edit or add possibly impt. details to this question.

4

1 回答 1

18

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.

After attaching gmodels, the call for reorder(factor) calls gdata:::reorder.factor. so, reorder(factor(group)) calls it.

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.

UPDATED

library attaches the import packages into loaded namespace.

> 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:

> 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:

see ?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.

So , in your case, 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
Error: object 'reorder.factor' not found

Probably this is whole scenario.

于 2012-06-12T22:38:49.590 回答