46

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

  1. 这是坏的
  2. 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)
}

我认为 usingimportFrom 不会加载整个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

那么,您知道如何在不进入我的环境的情况下导入description函数吗?memiscaggregate.formula

4

2 回答 2

28

你不能。

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

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

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

memisc示例中,两者都不成立。包中定义了aggregate泛型,statsformula中也定义了对象stats(基于该包定义as.formula[.formula等)由于它既不是memisc泛型也不memisc是对象,因此甚至可以看到效果(并且调度的方法to) ifmemisc只是加载但未附加。

有关此问题的另一个示例,但使用reorder.factor,请参阅Reordering factor 给出不同的结果,具体取决于加载的包

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

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

于 2013-11-07T17:14:55.220 回答
5

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

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

例子:
my_memisc_description <- memisc::description

于 2018-02-15T19:16:11.853 回答