56

I'm writing some R functions that employ some useful functions in other packages like stringr and base64enc. Is it good not to call library(...) or require(...) to load these packages first but to use :: to directly refer to the function I need, like stringr::str_match(...)?

Is it a good practice in general case? Or what problem might it induce?

4

1 回答 1

72

这一切都取决于上下文。

::如果存在名称空间冲突,则主要是必需的,来自不同包的具有相同名称的函数。当我加载dplyr包时,它提供了一个 function ,它与包中默认加载filter的函数发生冲突(并屏蔽)。所以如果我想使用函数的版本,我需要用. 这也为不加载大量包提供了动力。如果您真的只想要一个包中的一个功能,那么使用它可能比加载整个包更好,特别是如果您知道该包会屏蔽您想要使用的其他功能。filterstatsstatsstats::filter::

不是在代码中,而是在文本中,我确实觉得::非常有用。stats::filter比“包filter中的函数”键入要简洁得多stats

性能的角度来看,使用::. 长期 R-Core 开发团队成员 Martin Maechler 写道(在r-devel 邮件列表上(2017 年 9 月)

许多人似乎忘记了每次使用::都是一个 R 函数调用,与仅使用已经导入的名称相比,使用它的效率很低。

性能损失非常小,大约为几微秒,因此只有在需要高度优化的代码时才需要考虑。运行一行使用::一百万次的代码将比不使用的代码多花一两秒的时间::

就可移植性而言,最好在脚本顶部显式加载包,因为它可以轻松浏览前几行并查看需要哪些包,如有必要,在深入了解其他任何内容之前安装它们,即,在一个漫长的过程中进行到一半,而现在如果不重新开始就无法完成。

旁白:可以提出一个类似的论点来优先library()选择require()。如果包不存在,库将导致错误并停止,而 require 将发出警告但继续。如果你的代码有一个应急计划以防包不存在,那么一定要使用if (require(package)) ...,但如果你的代码在没有包的情况下会失败,你应该library(package)在顶部使用,这样它就会尽早而清晰地失败。

在您自己的包裹中

一般的解决方案是制作您自己的包,imports以便在说明文件中使用您需要使用的其他包。这些包将在您的包安装时自动安装,因此您可以在pkg::fun内部使用。或者,通过将它们也导入NAMESPACE文件中,您可以import选择整个包或选择性importFrom特定功能而不需要::. 对此意见不一。Martin Maechler(与上述相同的 r-devel 来源)说:

就我个人而言,我的印象是 :: 现在被“过度使用”了,特别是在我强烈主张在 NAMESPACE 中使用 importFrom() 的包中,所以所有这些都发生在包加载时,然后不在::包源中使用本身。

另一方面,RStudio 首席科学家 Hadley Wickham 在他的R Packages 书中说:

包在 中列出ImportsDESCRIPTION不在 中列出是很常见的NAMESPACE。事实上,这就是我的建议:列出DESCRIPTION安装包,然后始终使用pkg::fun(). 除非有充分的理由不这样做,否则最好是明确的。

两位受人尊敬的 R 专家给出了相反的建议,我认为可以公平地说,您应该选择最适合您的风格,并满足您对清晰度、效率和可维护性的需求。


如果您经常发现自己只使用另一个包中的一个功能,您可以复制代码并将其添加到您自己的包中。例如,我有一个个人使用%nin%的包,它从Hmisc包中借用,因为我认为它是一个很棒的功能,但我不经常使用来自Hmisc. 使用roxygen2,可以很容易地为借用的函数添加@author@references正确归因代码。执行此操作时还要确保软件包许可证兼容。

于 2014-04-23T00:49:04.183 回答