如何从另一个包中只导入一个函数,而不加载整个命名空间

Posted

技术标签:

【中文标题】如何从另一个包中只导入一个函数,而不加载整个命名空间【英文标题】:How to import only one function from another package, without loading the entire namespace 【发布时间】:2013-11-19 05:47:24 【问题描述】:

假设我正在开发一个名为foo 的包,它想使用memisc 包中的description 函数。我不想导入整个 memisc 命名空间,因为:

    很糟糕 memisc 覆盖了基本的 aggregate.formula 函数,这破坏了几件事。例如,example(aggregate) 会惨遭失败。

该软件包包括以下文件:

描述

Package: foo
Version: 0.0
Title: Foo
Imports:
    memisc
Collate:
    'foo.R'

命名空间

export(bar)
importFrom(memisc,description)

R/foo.R

##' bar function
##'
##' @param x something
##' @return nothing
##' @importFrom memisc description
##' @export

`bar` <- function(x) 
    description(x)

我认为使用importFrom 不会加载整个memisc 命名空间,而只会加载namespace::description,但事实并非如此。从香草 R 开始:

R> getS3method("aggregate","formula")
## ... function code ...
## <environment: namespace:stats>
R> library(foo)
R> getS3method("aggregate","formula")
## ... function code ...
## <environment: namespace:memisc>
R> example(aggregate)
## Fails

那么,您知道如何在我的环境中不获取aggregate.formula 的情况下从memisc 导入description 函数吗?

【问题讨论】:

@HongOoi 不,这行不通。 :: 手册页说使用它会加载整个命名空间,我已经测试过了。 @HongOoi 您可以在 R vanilla 会话中尝试以下操作,您仍然会从memisc 获得aggregate.formulamemisc::description ; getS3method("aggregate","formula") 我想知道这里的实际问题在多大程度上只是 memisc 作者不应该掩盖aggregate.formula @joran 完全同意你的看法。至少,对我来说,这将是一个很好的提醒,永远不要覆盖基本函数。 无法从命名空间加载单个函数(不加载命名空间),因为 R 无法知道该函数需要哪些其他函数。 【参考方案1】:

你不能。

如果您在Imports: 字段中声明memisc,则在加载包时将加载命名空间,并且您的包可以找到导出的对象。 (如果您在Depends: 中指定它,命名空间将被加载并附加到搜索路径,这使得任何代码都可以找到导出的对象。)

加载命名空间的一部分是向泛型注册方法。 (我查看了但找不到说明这一点的规范文档;我将呼吁在NAMESPACE 文件中将函数声明为 S3 方法作为证据这一事实。)定义的方法与泛型保持一致并具有可见性泛型函数的名称(或者,可能是泛型函数的命名空间)。

通常,一个包会为它创建的泛型或它定义的类定义一个方法。 S3 对象系统没有正式定义 S3 类(或创建该类的包)的机制,但一般的想法是,如果包定义了返回具有该类属性的对象的函数(并且是唯一的包确实),该类是该包的类。如果这两个条件中的任何一个成立,就不会有问题。如果包中定义了泛型,则只有在附加包的情况下才能找到;如果类是在包中定义的,那么该类的对象只有在附加和使用包的情况下才会存在(并因此被分派)。

memisc 示例中,两者都不成立。 aggregate 泛型在stats 包中定义,formula 对象也在stats 包中定义(基于定义as.formula[.formula 等的包)因为它既不是@ 987654334@ 的泛型或 memisc 的对象,如果只是加载但未附加 memisc,甚至可以看到效果(以及调度到的方法)。

有关此问题的另一个示例,但使用reorder.factor,请参阅Reordering factor gives different results, depending on which packages are loaded。

一般来说,将方法添加到包不控制对象或泛型的泛型中是不好的做法;如果它覆盖核心包中的方法,则更是如此;如果它不是核心包中现有功能的向后兼容功能,那就太糟糕了。

对于您的示例,您最好将 memisc::describe 的代码复制到您的包中,尽管这种方法有其自身的问题和警告。

【讨论】:

非常感谢您提供清晰详细的答案和建议。作为一种解决方法,我想我只需将memisc 放入Suggests 并在需要时使用require 加载包,正如@hadley 所建议的那样:***.com/questions/5260079/…【参考方案2】:

需要注意的是,我不太熟悉 R 环境和命名空间,也不知道这是否可以在包中工作——我在编程中使用的一种解决方法是使用 :: 将函数复制到我自己的功能。

加载整个包可能会产生未知的后果,正如 cmets 对 OP 的问题所讨论的那样,但它似乎没有将包的函数名称附加到 R 命名空间并屏蔽现有函数名称。

示例:my_memisc_description &lt;- memisc::description

【讨论】:

以上是关于如何从另一个包中只导入一个函数,而不加载整个命名空间的主要内容,如果未能解决你的问题,请参考以下文章

如何检查 Python 包中的任何模块是不是从另一个包导入?

从另一个文件导入变量?

戈朗。从包中只导入一个文件

如何从另一个组件返回到另一个组件而不以角度重新加载组件?

如何在 NPM 包中使用 webpack 动态导入?

系统的助手函数