我正在编写一些R函数,这些函数在stringr
和base64enc
等其他包中使用了一些有用的函数。是不是先调用library(...)
或require(...
)来加载这些包,而是使用::
直接引用我需要的函数,例如stringr::str_match(...)
?
一般情况下这是一个好习惯吗?或者它会引起什么问题?
答案 0 :(得分:45)
这一切都取决于背景。
如果存在命名空间冲突,则 ::
主要是必需的,来自具有相同名称的不同包的函数。当我加载dplyr
包时,它提供了一个函数filter
,它与filter
包中默认加载的stats
函数冲突(并屏蔽)。因此,如果我想使用该功能的stats
版本,我需要使用stats::filter
来调用它。这也为不加载大量软件包提供了动力。如果你真的只想要一个包中的一个函数,最好使用::
而不是加载整个包,特别是如果你知道包会掩盖你想要使用的其他函数。
不在代码中,但在文本中,我发现::
非常有用。键入stats::filter
而不是" filter
包中的stats
函数"更为简洁。
从效果的角度来看,使用::
的价格非常低。 Martin Maechler写道(r-devel mailing list (Sept 2017))
许多人似乎忘记了
::
的每次使用都是R 与仅使用相比,函数调用和使用它是低效的 已导入的名称。
性能损失非常小,大约几微秒,所以当您需要高度优化的代码时,它只是一个问题。运行使用::
一百万次的代码行将比不使用::
的代码长一两秒。
就可移植性而言,在脚本顶部显式加载包是很好的,因为它可以轻松浏览前几行并查看需要的包,必要时安装它们。其他任何事情都太深了,也就是说,在没有重新开始的情况下完成一个现在无法完成的漫长过程的中途。
除了:可以使用类似的参数来优先library()
而不是require()
。如果包不在那里,库将导致错误并停止,而require将发出警告但仍继续。如果您的代码有一个应急计划,以防包裹不在那里,那么请务必使用if (require(package)) ...
,但如果您的代码在没有包裹的情况下失败,您应该在顶部使用library(package)
它很早就清楚地失败了。 (感谢Hugh和BondedDust的评论。)
一般的解决方案是创建自己的包,imports
您需要在DESCRIPTION文件中使用的其他包。安装软件包时将自动安装这些软件包,因此您可以在内部使用pkg::fun
。或者,通过在NAMESPACE
文件中导入它们,您可以import
整个包或选择性importFrom
特定功能,而不需要::
。意见不同。 R-Core成员Martin Maechler(与上述相同的r-devel来源)说:
就个人而言,我的印象是:是 很多"过度使用"如今,特别是在我非常强烈的包装中 主张在NAMESPACE中使用importFrom(),所以这一切都发生了 在程序包加载时,然后不使用程序包中的
::
消息来源。
另一方面,知名包装开发商Hadley Wickham在R Packages book中说:
通常,
Imports
中的DESCRIPTION
列出了包,但NAMESPACE
中却没有。实际上,这就是我的建议:在DESCRIPTION
中列出包以便安装它,然后始终使用pkg::fun()
显式引用它。除非有充分的理由不这样做,否则最好是明确的。
有两位受人尊敬的R专家提出相反的建议,我认为你应该选择最适合你的风格并满足你对清晰度,效率和可维护性的需求。
如果您经常发现自己只使用其他软件包中的一个函数,则可以复制代码并将其添加到您自己的软件包中。例如,我有一个供个人使用的软件包,可以从%nin%
软件包借用Hmisc
,因为我认为这是一个很棒的功能,但我不经常使用{{1}中的任何其他内容。 1}}。使用Hmisc
,可以轻松添加roxygen2
和@author
以正确归属借用函数的代码。此外,还要确保包许可证兼容。