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

时间:2022-03-09 16:55:11

Suppose I'm developing a package, called foo, which would like to use the description function from the memisc package. I don't want to import the whole memisc namespace because :

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

  1. It is bad
  2. 它是坏的
  3. memisc overrides the base aggregate.formula function, which breaks several things. For example, example(aggregate) would fail miserably.
  4. memisc覆盖基聚合。公式函数,它打破了一些东西。例如,示例(聚合)将严重失败。

The package includes the following files :

该软件包包括以下文件:

DESCRIPTION

描述

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

NAMESPACE

名称空间

export(bar)
importFrom(memisc,description)

R/foo.R

R / foo.R

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

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

I'd think that using importFrom would not load the entire memisc namespace, but only namespace::description, but this is not the case. Starting with a vanilla R :

我认为使用importFrom不会加载整个memisc名称空间,而只会加载名称空间::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

So, do you know how I can import the description function from memisc without getting aggregate.formula in my environment ?

你知道我如何从memisc中导入描述函数而不需要聚合吗?环境中的公式?

2 个解决方案

#1


22  

You can't.

你不能。

If you declare memisc in the Imports: field, the namespace will be loaded when the package is loaded and the exported objects will be findable by your package. (If you specify it in Depends:, the namespace will be loaded and attached to the search path which makes the exported objects findable by any code.)

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

Part of loading a namespace is registering methods with the generic. (I looked but couldn't find a canonical documentation that says this; I will appeal to the fact that functions are declared as S3 methods in the NAMESPACE file as evidence.) The defined methods are kept with the generic and have the visibility of the generic function (or, perhaps, the generic function's namespace).

加载名称空间的一部分是向泛型注册方法。(我找了一下,但是找不到一个权威的文件来说明这一点;我将求助于这样一个事实,即函数在名称空间文件中声明为S3方法作为证据。定义的方法与泛型保持一致,并具有泛型函数的可见性(或者,可能是泛型函数的名称空间)。

Typically, a package will define a method either for a generic it creates or for a class it defines. The S3 object system does not have a mechanism for formally defining an S3 class (or what package created the class), but the general idea is that if the package defines functions which return an object with that class attribute (and is the only package that does), that class is that package's class. If either of these two conditions hold, there will not be a problem. If the generic is defined in the package, it can only be found if the package is attached; if the class is defined in the package, objects of that class would only exist (and therefore be dispatched on) if the package is attached and used.

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

In the memisc example, neither holds. The aggregate generic is defined in the stats package and the formula object is also defined in the stats package (based on that package defining as.formula, [.formula, etc.) Since it is neither memisc's generic nor memisc's object, the effects can be seen even (and the method dispatched to) if memisc is simply loaded but not attached.

在memisc示例中,两者都不成立。聚合泛型在stats包中定义,公式对象也在stats包中定义(基于定义为公式,(。由于memisc既不是memisc的泛型,也不是memisc的对象,所以如果只是加载了memisc,而没有附加memisc,就可以看到它的效果(以及发送给它的方法)。

For another example of this problem, but with reorder.factor, see Reordering factor gives different results, depending on which packages are loaded.

关于这个问题的另一个例子,但是重新排序。因子,参见重新排序因子,根据装载的包给出不同的结果。

In general, it is not good practice to add methods to generics for which the package does not control either the object or the generic; doubly so if it overrides a method in a core package; and egregiously so if it is not a backwards compatible function to the existing function in the core packages.

一般来说,在包既不控制对象也不控制泛型的泛型中添加方法是不好的做法;如果它覆盖核心包中的一个方法,则加倍地如此;如果它不是一个与核心包中现有函数向后兼容的函数,那就太可怕了。

For your example, you may be better off copying the code for memisc::describe into your package, although that approach has its own problems and caveats.

对于您的示例,最好将memisc::describe复制到您的包中,尽管这种方法有自己的问题和注意事项。

#2


0  

With the caveat that I'm not too familiar with the R environment and namespaces, nor whether this would work in a package — a workaround I've used in programming is to use :: to copy the function into my own function.

需要注意的是,我不太熟悉R环境和名称空间,也不知道这在包中是否适用——我在编程中使用的一个变通方法是:::将函数复制到我自己的函数中。

It may have unknown consequences of loading the whole package, as discussed in the comments to OP's question, but it seems to not attach the package's function names to R namespace and mask existing function names.

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

Example:
my_memisc_description <- memisc::description

例如:my_memisc_description < - memisc:描述

#1


22  

You can't.

你不能。

If you declare memisc in the Imports: field, the namespace will be loaded when the package is loaded and the exported objects will be findable by your package. (If you specify it in Depends:, the namespace will be loaded and attached to the search path which makes the exported objects findable by any code.)

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

Part of loading a namespace is registering methods with the generic. (I looked but couldn't find a canonical documentation that says this; I will appeal to the fact that functions are declared as S3 methods in the NAMESPACE file as evidence.) The defined methods are kept with the generic and have the visibility of the generic function (or, perhaps, the generic function's namespace).

加载名称空间的一部分是向泛型注册方法。(我找了一下,但是找不到一个权威的文件来说明这一点;我将求助于这样一个事实,即函数在名称空间文件中声明为S3方法作为证据。定义的方法与泛型保持一致,并具有泛型函数的可见性(或者,可能是泛型函数的名称空间)。

Typically, a package will define a method either for a generic it creates or for a class it defines. The S3 object system does not have a mechanism for formally defining an S3 class (or what package created the class), but the general idea is that if the package defines functions which return an object with that class attribute (and is the only package that does), that class is that package's class. If either of these two conditions hold, there will not be a problem. If the generic is defined in the package, it can only be found if the package is attached; if the class is defined in the package, objects of that class would only exist (and therefore be dispatched on) if the package is attached and used.

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

In the memisc example, neither holds. The aggregate generic is defined in the stats package and the formula object is also defined in the stats package (based on that package defining as.formula, [.formula, etc.) Since it is neither memisc's generic nor memisc's object, the effects can be seen even (and the method dispatched to) if memisc is simply loaded but not attached.

在memisc示例中,两者都不成立。聚合泛型在stats包中定义,公式对象也在stats包中定义(基于定义为公式,(。由于memisc既不是memisc的泛型,也不是memisc的对象,所以如果只是加载了memisc,而没有附加memisc,就可以看到它的效果(以及发送给它的方法)。

For another example of this problem, but with reorder.factor, see Reordering factor gives different results, depending on which packages are loaded.

关于这个问题的另一个例子,但是重新排序。因子,参见重新排序因子,根据装载的包给出不同的结果。

In general, it is not good practice to add methods to generics for which the package does not control either the object or the generic; doubly so if it overrides a method in a core package; and egregiously so if it is not a backwards compatible function to the existing function in the core packages.

一般来说,在包既不控制对象也不控制泛型的泛型中添加方法是不好的做法;如果它覆盖核心包中的一个方法,则加倍地如此;如果它不是一个与核心包中现有函数向后兼容的函数,那就太可怕了。

For your example, you may be better off copying the code for memisc::describe into your package, although that approach has its own problems and caveats.

对于您的示例,最好将memisc::describe复制到您的包中,尽管这种方法有自己的问题和注意事项。

#2


0  

With the caveat that I'm not too familiar with the R environment and namespaces, nor whether this would work in a package — a workaround I've used in programming is to use :: to copy the function into my own function.

需要注意的是,我不太熟悉R环境和名称空间,也不知道这在包中是否适用——我在编程中使用的一个变通方法是:::将函数复制到我自己的函数中。

It may have unknown consequences of loading the whole package, as discussed in the comments to OP's question, but it seems to not attach the package's function names to R namespace and mask existing function names.

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

Example:
my_memisc_description <- memisc::description

例如:my_memisc_description < - memisc:描述