通过::调用包中的函数是一个好习惯吗?

Kun*_*Ren 39 scope namespaces r scoping qualified-name

我正在写使用一些有用的功能像其他一些包R里面的函数stringrbase64enc.是不是首先要调用library(...)或者require(...加载这些包,而是::用来直接引用我需要的函数,比如stringr::str_match(...)

在一般情况下这是一个好习惯吗?或者它会引起什么问题?

Gre*_*gor 49

这一切都取决于背景.

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

不是在代码中,而是在文本中,我觉得::非常有用.键入stats::filter比" 包中的filter功能" 简洁得多stats.

性能角度来看,使用的价格非常低::.Martin Maechler写道(在r-devel邮件列表上(2017年9月))

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

性能损失非常小,大约几微秒,因此当您需要高度优化的代码时,这只是一个问题.运行使用::一百万次的代码行将比不使用的代码长一两秒::.

就可移植性而言,在脚本顶部显式加载包是很好的,因为它可以很容易地浏览前几行,看看需要哪些包,必要时安装它们,然后再深入其他任何包,即,如果没有重新开始,现在就无法完成一个漫长的过程.

除了:一个类似的说法可以做出更喜欢library()require().如果包不存在,库将导致错误并停止,而require将发出警告但仍继续.如果您的代码有一个应急计划,以防包裹不在那里,那么一定要使用if (require(package)) ...,但是如果您的代码在没有包的情况下失败,您应该library(package)在顶部使用,以便尽早及清楚地失败.(感谢Hugh和BondedDust的评论.)

编写自己的包

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

就个人而言,我得到的印象是::是多"过度使用"的今天,特别是在包哪里我强烈主张使用importFrom()中的命名空间,所以这一切都发生在包加载时间,然后使用::的包源本身.

另一方面,着名的软件包开发人员Hadley Wickham在他的R Packages书中说:

这是常见的事情被列出的软件包ImportsDESCRIPTION,而不是在NAMESPACE.事实上,这就是我的建议:列出软件包DESCRIPTION以便安装它,然后总是明确地引用它pkg::fun().除非有充分的理由不这样做,否则最好是明确的.

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


如果您经常发现自己只使用另一个包中的一个函数,则可以复制代码并将其添加到您自己的包中.例如,我有一个个人使用%nin%Hmisc包,借用了包,因为我认为这是一个很好的功能,但我不经常使用其他任何东西Hmisc.使用roxygen2,可以轻松添加@author@references正确归属借用函数的代码.执行此操作时,还要确保包许可证兼容.

  • 在脚本顶部使用`library(...)`的另一个好处是,如果有人试图在没有安装包的情况下"源"你的文件,`source`命令将提前失败(而不是在可能长的数据加载或操作). (6认同)
  • @shujaa是的,它应该在DESCRIPTION导入中,但它不应该在NAMESPACE导入(pkg)或importFrom(pkg,foo)中(我认为我原来的评论有点令人困惑) (4认同)
  • @BondedDust 在这种情况下,最好使用 `stop` 或 `warning` 而不是 `cat`。 (2认同)
  • 如果您正在编写一个包,我认为最好使用 `::` 而不是命名空间导入或导入(除非您使用来自其他包的 _lot_ 函数) (2认同)
  • 可能会添加关于代码可读性的简短评论。让每个函数调用都以包名称为前缀会使代码变得混乱。特别是某些函数调用是另一个函数调用的参数等...(常见于 tidyr) (2认同)