如何通过调用在其名称空间中没有它的函数来找到未附加包中的非导入方法?

Jos*_*ien 29 namespaces r scoping

R命名空间充当其关联包中所有函数的直接环境.换句话说,当函数bar()从包调用另一个函数时,R首次评估器搜索中的其他功能<environment: namespace:foo>,那么"imports.foo",<environment: namespace:base>,<environment: R_GlobalEnv>,等下键入返回的搜索列表search().

命名空间的一个很好的方面是它们可以使包像行为更好的公民:未经输出的函数<environment: namespace:foo>和函数imports:foo仅可用:(a)foo中的函数; (b)从foo进口的其他包裹; 或(c)通过完全合格的函数调用,如foo:::bar().

或者直到最近才想到......

行为

这个最近的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
Run Code Online (Sandbox Code Playgroud)

它的直接原因

@Andrie通过指出gmodels从包gdata导入来回答原始问题,包中包含一个reorder.factor被调度到第二次调用的函数transform().T1不同之处T2在于,第一个是由stats:::reorder.default()第二个计算的,第二个是由gdata:::reorder.factor().

我的问题

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

(答案应该包括对范围规则的解释,这些规则从涉及统计数据基础包中的函数的调用引导到gdata中看似隐藏得很好的方法.)


还可能有用的细节

  1. 无论是gdata:::reorder.factor,也不是GDATA包作为一个整体被明确进口gmodels.以下是gmodelsNAMESPACE文件中的import*指令:

    importFrom(MASS, ginv)
    importFrom(gdata, frameApply)
    importFrom(gdata, nobs)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 有因为没有方法reorder()transform()<environment: namespace:gmodels>,也不在"imports:gmodels":

    ls(getNamespace("gmodels"))
    ls(parent.env(getNamespace("gmodels")))
    
    Run Code Online (Sandbox Code Playgroud)
  3. 分离gmodels不会恢复reorder()行为:gdata:::reorder.factor()仍然会被调度:

    detach("package:gmodels")
    T3 <- transform(data, group=reorder(group,-num))
    identical(T3, T2)
    # [1] TRUE
    
    Run Code Online (Sandbox Code Playgroud)
  4. reorder.factor() 未存储在基本环境中的S3方法列表中:

    grep("reorder", ls(.__S3MethodsTable__.))
    # integer(0)
    
    Run Code Online (Sandbox Code Playgroud)

过去几天的R聊天线程包括一些额外的想法.感谢Andrie,Brian Diggs和Gavin Simpson(和其他人一起)应该随意编辑或添加可能的impt.这个问题的细节.

koh*_*ske 16

我不确定我是否正确理解了你的问题,但重点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"    
Run Code Online (Sandbox Code Playgroud)

以防万一,reorder通用存在于namespace:stats:

> r <- ls(.__S3MethodsTable__., envir = asNamespace("stats"))
> r[grep("reorder", r)]
[1] "reorder"            "reorder.default"    "reorder.dendrogram"
Run Code Online (Sandbox Code Playgroud)

并了解更多详情

呼叫reorder将在两个环境中搜索S3generics:

看到 ?UseMethod

首先在调用泛型函数的环境中,然后在定义泛型的环境的注册数据库中(通常是命名空间).

然后,loadNamespace将S3函数注册到命名空间.

所以,在你的情况下,library(gmodels)- > loadNamespace(gdata)- > registerS3Methods(gdata).

在此之后,您可以通过以下方式找到它:

> methods(reorder)
[1] reorder.default*    reorder.dendrogram* reorder.factor*    

   Non-visible functions are asterisked
Run Code Online (Sandbox Code Playgroud)

但是,由于reorder.factor未在搜索路径中附加,因此您无法直接访问它:

> reorder.factor
Error: object 'reorder.factor' not found
Run Code Online (Sandbox Code Playgroud)

可能这是整个场景.