将非 S3 基本函数重新定义为 R 包中的 S3 函数是不好的风格吗?

Posted

技术标签:

【中文标题】将非 S3 基本函数重新定义为 R 包中的 S3 函数是不好的风格吗?【英文标题】:Is it bad style to redefine non-S3 base functions as S3 functions in an R package? 【发布时间】:2017-02-14 20:58:58 【问题描述】:

所以我正在开发一个使用 S3 类的 R 包,如果我可以使用 sample 作为我的一个类的方法,那就太好了。但是,base 已经将sample 声明为非 S3 函数,所以我想知道的是:

将非 S3 base 函数(例如 sample)重新定义为 S3 函数是不是很糟糕?这会给我的软件包的用户带来麻烦吗?

您可以重新定义 sample 并保持 base 函数正常工作的方法是:

sample.default <- base::sample
sample <- function(x, ...) 
  UseMethod("sample")

# This allows me to define a new sample method for my_special_class
sample.my_special_class <- function(...) ...

但我不确定这是否会导致任何麻烦或命名空间问题,例如,在加载其他包时。我也注意到没有多少包重新定义sample,例如,dplyr 使用sample_n,igraph 使用sample_,我认为这可能有一些原因......

【问题讨论】:

如果您还没有,也许您可​​以创建自己的类并定义一个sample.yourclassname 来处理您的类。通过这种方式,您可以保持使用泛型函数的一致性。 @RomanLuštrik:这行不通,因为base::sample 不是通用的。如果它是通用的,则没有理由在您的包中重新定义它;你只需注册你的方法。 @JoshuaUlrich bah,你打败了我。刚刚在您发帖前几秒钟检查了功能。你是对的。回到绘图板。 见***.com/questions/41884629/… 【参考方案1】:

“风格”是否糟糕主要取决于意见。但是编写 R 扩展,Section 7.1 - Adding new generics 告诉您如何添加新的泛型来屏蔽基本的基本/推荐功能。也就是说,该部分明确警告您提出的解决方案:

...一个包可以接管基础包中的一个功能,并通过类似的方式使其通用

 foo <- function(object, ...) UseMethod("foo")
 foo.default <- function(object, ...) base::foo(object)

本手册的早期版本建议分配foo.default &lt;- base::foo。这不是一个好主意,因为它会在安装时捕获基本功能,并且可能会随着 R 的修补或更新而更改。

其他人可能遇到的一个问题是,如果另一个包也将summary 注册为泛型。然后根据您的包或其他包的包需要决定向哪个泛型注册他们的方法。

没有多少包重新定义sample,因为屏蔽基本/推荐函数通常不是一个好主意。这使用户有可能在顶层获得不同的行为,具体取决于您的包是否已加载。

您肯定要避免的一件事是在基本/推荐(或高度使用)包中屏蔽泛型。这样做可以防止在顶层进行方法分派,从而让期望泛型工作的用户感到头疼(例如dplyr::lag)。

【讨论】:

如果我对手册的理解正确,CRAN 建议您定义 sample.default &lt;- function(x, ...) base::sample(x, ...) 并认为这是允许的。 @Benjamin 为什么不创建自己的类并扩展泛型来处理该类? @RomanLuštrik 根据大数定律,它最终必须发生。 :) @Benjamin 我的人生策略。 @RasmusBååth:我提到这是一个可能的问题,但可能性很小。包需要使用 both 包来创建通用并且想要注册sample 方法。

以上是关于将非 S3 基本函数重新定义为 R 包中的 S3 函数是不好的风格吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何不覆盖泛型方法

R语言面向对象编程:S3和R6

R语言中,简单的S3和S4类的定义

猪用户定义函数中的 aws Amazon S3 客户端凭证

Rails - 为 S3 迁移重新保存所有模型

r 将Amazon S3中的RDS加载到磁盘和内存中