如何通过调用名称空间中没有它的函数来找到未附加包中的非导入方法? [英] How can a non-imported method in a not-attached package be found by calls to functions not having it in their namespace?

查看:8
本文介绍了如何通过调用名称空间中没有它的函数来找到未附加包中的非导入方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

R 命名空间充当其关联包中所有函数的直接环境.换句话说,当 foo 包中的函数 bar() 调用另一个函数时,R evaluator 首先在 中搜索另一个函数;,然后在 "imports.foo", <environment: namespace:base>, ,依此类推,通过键入 search() 返回的搜索列表.

An R namespace acts as the immediate environment for all functions in its associated package. 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().

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

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; (b) to other packages that import from foo; or (c) via fully qualified function calls like foo:::bar().

直到最近我还是这么认为的......

Or so I thought until recently...

这个最近的 SO question 强调了这样一个案例,在该案例中,一个隐藏在其包命名空间中的函数仍然通过调用一个看似不相关的函数而被发现:

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:

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() 的第二次调用内部.T1T2 不同,因为第一个由 stats:::reorder.default() 计算,第二个由 gdata:::reorder.factor().

Its immediate cause

@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(). T1 differs from T2 because the first is calculated by stats:::reorder.default() and the second by gdata:::reorder.factor().

在上面对transform(data, group=reorder(...))的调用中,reorder的调度机制是怎么找到然后调度到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()?

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

(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.)

  1. gdata:::reorder.factorgdata 包都不是由 gmodels 显式导入的.以下是 gmodelsNAMESPACE 文件中的 import* 指令:

  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)

  • <environment: namespace:gmodels> 中没有 reorder()transform() 的方法,也没有在 "imports:gmodels":

  • There are no methods for reorder() or transform() in <environment: namespace:gmodels>, nor in "imports:gmodels":

    ls(getNamespace("gmodels"))
    ls(parent.env(getNamespace("gmodels")))
    

  • 分离 gmodels 不会恢复 reorder() 的行为:gdata:::reorder.factor() 仍然会得到发送:

  • 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() 未存储在基础环境中的 S3 方法列表中:

  • 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,他们(和其他人)应该可以随意编辑或添加可能的 impt.这个问题的详细信息.

    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.

    推荐答案

    我不确定我是否正确理解了你的问题,但重点是 group 是字符向量,而 data$group 是因素.

    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.

    附加 gmodels 后,对 reorder(factor) 的调用调用 gdata:::reorder.factor.所以,reorder(factor(group)) 调用它.

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

    transform中,函数是在第一个参数的环境中计算的,所以在T2 <- transform(data, group = reorder(group,-num)), 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.

    更新

    library 将导入包附加到加载的命名空间中.

    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"    
    

    以防万一,reorder 泛型存在于 namespace:stats:

    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"
    

    更多详情

    reorder 的调用将在两个 env 中搜索 S3generics:

    The call of reorder will search the S3generics in two envs:

    ?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 函数注册到命名空间.

    then, loadNamespace registers the S3 functions to the namespace.

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

    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
    

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

    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
    

    可能这就是整个场景.

    这篇关于如何通过调用名称空间中没有它的函数来找到未附加包中的非导入方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆