更好地解释何时使用 Imports/Dependes

编写 R 扩展”手册就何时使用 Import 或 Depend 提供了以下指导:

一般规则是

  • 其命名空间仅用于使用库(pkgname)加载包的包必须列在“ Imports”字段中,而不是列在 “视情况”字段。
  • 使用库(pkgname)成功加载包时需要附加的包必须仅列在“依赖”字段中。

有人能说清楚点吗?我如何知道什么时候我的包只需要加载名称空间,什么时候我需要一个包附加?两者的例子是什么?我认为典型的包只是一组函数的集合,这些函数有时会调用其他包中的函数(其中一些工作已经编码完成)。这是上面的第一种情况还是第二种情况?

剪辑

我写了一个 博客文章,其中有一节是关于这个特定主题的(搜索“ Imports v Dependes”)。视觉效果让人更容易理解。

31793 次浏览

SfDA 的钱伯斯说,当这个包使用“名称空间”机制时,要使用“导入”,因为现在所有的包都要求使用“名称空间”,所以答案可能总是使用“导入”。在过去,可以在没有实际名称空间的情况下加载包,在这种情况下,需要使用 Dependes。

"Imports""Depends"更安全(而且使用它的软件包相对于使用 "Depends"的其他软件包来说也是一个“更好的公民”)。

"Depends"指令试图通过将另一个包附加到主搜索路径(即 search()返回的环境列表)来确保来自另一个包的函数可用。但是,如果稍后加载的另一个包在搜索路径的前面放置了一个名称相同的函数,则此策略可能会受到阻碍。Chambers (在苏打水里)使用函数 "gam"的示例,它在 gammgcv包中都可以找到。如果加载另外两个包,其中一个取决于 gam,另一个取决于 mgcv,那么通过调用 gam()找到的函数将取决于这两个包的附加顺序。情况不妙。

"Imports"指令应该用于任何其功能将放置在 <imports:packageName>中(在 <namespace:packageName>之后立即搜索)的支持包,而不是在常规搜索路径上。如果上面示例中的任何一个包使用了 "Imports"机制(这也需要 NAMESPACE文件中的 importimportFrom指令) ,事情将从两个方面得到改进。(1)软件包本身可以控制使用哪个 mgcv函数。(2)通过保持主搜索路径远离导入的对象,它甚至不会打破其他包对另一个 mgcv函数的依赖性。

这就是为什么使用名称空间是一个很好的实践,为什么现在 CRAN 强制使用名称空间,特别是为什么使用 "Imports"比使用 "Depends"更安全。


编辑添加了一个重要的警告:

不幸的是,对于上面的建议,有一个 常见的例外: 如果你的软件包依赖于一个软件包 A,而这个软件包本身就是另一个软件包 B上的 "Depends",那么你的软件包很可能需要附加 A"Depends指令。

这是因为 编写包 ABC0中的函数时,预期包 ABC1及其函数将附加到 search()路径

"Depends"指令将加载并附加包 A,在这一点上,包 A自己的 "Depends"指令将在链式反应中导致包 B也被加载并附加。然后,包 A中的函数将能够找到它们所依赖的包 B中的函数。

一个 "Imports"指令将加载但 没有附加软件包 A和将 A0加载 A1附加软件包 B。(毕竟,"Imports"期望包编写器使用名称空间机制,而包 A将使用 "Imports"指向它需要访问的 B中的任何函数。)函数对依赖于包 B中的函数的包 A中的任何函数的调用都将因此失败。

唯一的两个解决办法是:

  1. 让包使用 "Depends"指令附加包 A
  2. 从长远来看,更好的做法是与包 A的维护人员联系,要求他们更仔细地构建自己的名称空间(用 这个相关的答案中 Martin Morgan 的话来说)。

Hadley Wickham 给出了一个简单的解释(http://r-pkgs.had.co.nz/namespace.html) :

DependsImports中列出一个包可以确保它是 主要的区别在于 Imports只是 加载包,Depends连接它。没有其他 分歧

除非有一个很好的理由,否则,你应该总是列出 这是因为一个好的包是 自我包含,并最大限度地减少对全球环境的变化 (包括搜索路径)。 < strong > 唯一的例外是,如果您的包是 设计用于与另一个包结合使用。例如, 模拟包是建立在素食之上的,没有素食是没有用的 纯素,所以它在 Depends中有纯素而不是 Imports。同样, Ggplot2应该真正依赖于大小,而不是导入它。

这里有一个简单的问题可以帮助你决定使用哪种方法:

您的软件包是否要求 最终用户能够直接访问另一个软件包的功能?

  • NO-> Imports (最常见的答案)
  • 是-> 视情况而定

只有当你的软件包是另一个软件包的附加组件或伴侣时,你的终端用户才会使用你的软件包和他们代码中的“ Depend”软件包中的函数。如果您的最终用户将只与您的功能进行接口,而其他软件包将只在幕后工作,那么使用“导入”代替。

需要注意的是,如果像通常那样向“ Imports”添加一个包,那么代码将需要引用该包中的函数,使用完整的名称空间语法,例如 dplyr::mutate(),而不仅仅是 mutate()。它使得代码读起来有点笨重,但是为了更好地保持软件包卫生,这只是一个很小的代价。