我正在开发我的第一个R包,对于来说,对于我来说尚不清楚的东西是在Description文件中导入。我浏览了很多说明软件包结构的指南,但是找不到我的问题的答案,所以这是我的情况。
f
,因此其定义将在顶部带有正确的@export
roxygen注释。 f
调用了我不想导出的子例程hidden
。函数hidden
也使用其他软件包,例如X
软件包。 因为对
X
的调用是在hidden
函数内部,所以我的函数@import X
中没有标签f
。因此,我在我的DESCRIPTION文件中的X
中添加了Imports
包,希望在那里指定相关的依赖项。但是,当我使用
devtools::document()
时,生成的NAMESPACE不包含X
的条目。我可以看到发生这种情况的原因:解析器只是在roxygen注释中找不到f
的标志,并且在运行时对f
的调用崩溃,因为缺少X
。现在,我可以通过在
X
的导入中指定f
来修复所有问题。但是为什么机制如此棘手?或者,类似地,为什么我在DESCRIPTION中的导入与NAMESPACE中的导入不匹配? 最佳答案
我的理解是,有三种“正确”的方式来进行导入。 “正确”是指它们将通过CRAN检查并正常运行。选择哪个选项是要平衡各种优势,并且在很大程度上是主观的。
我将在下面使用术语回顾这些选项
primary_function
您要导出的包中的函数hidden
primary_function
所使用的软件包中未导出的函数thirdpartypkg::blackbox
,blackbox
是从thirdpartypkg
包中导出的函数。 选项1(无直接导入/显式函数调用)
我认为这是最常见的方法。在Description文件中声明了
thirdpartypkg
,但是在NAMESPACE文件中没有从thirdpartypkg
导入任何内容。在此选项中,是所必需的,以便使用thirdpartypkg::blackbox
构造来获得所需的行为。# DESCRIPTION
Imports: thirdpartypkg
# NAMESPACE
export(primary_function)
#' @name primary_function
#' @export
primary_function <- function(x, y, z){
# do something here
hidden(a = y, b = x, z = c)
}
# Unexported function
#' @name hidden
hidden <- function(a, b, c){
# do something here
thirdpartypkg::blackbox(a, c)
}
选项2(直接导入/无显式函数调用)
在此选项中,您直接导入
blackbox
函数。这样做之后,就不再需要使用thirdpartypkg::blackbox
了;您可以简单地调用blackbox
,就好像它是软件包的一部分一样。 (从技术上讲,您将其导入了 namespace ,因此无需获取另一个 namespace 即可获取它)# DESCRIPTION
Imports: thirdpartypkg
# NAMESPACE
export(primary_function)
importFrom(thirdpartypkg, blackbox)
#' @name primary_function
#' @export
primary_function <- function(x, y, z){
# do something here
hidden(a = y, b = x, z = c)
}
# Unexported function
#' @name hidden
#' @importFrom thirdpartypkg blackbox
hidden <- function(a, b, c){
# do something here
# I CAN USE blackbox HERE AS IF IT WERE PART OF MY PACKAGE
blackbox(a, c)
}
选项3(直接导入/显式函数调用)
您的最后一个选项组合了前两个选项,并将
blackbox
导入您的 namespace ,然后使用thirdpartypkg::blackbox
构造来利用它。从有效的意义上来说,这是“正确的”。但这可以说是浪费和多余的。我说这是浪费和多余的原因是,将
blackbox
导入到您的 namespace 后,您再也不会使用它了。相反,您在blackbox
命名空间中使用了thirdpartypkg
。从本质上讲,blackbox
现在存在于两个 namespace 中,但是只有其中一个已被使用。这就引出了为什么要完全制作副本的问题。# DESCRIPTION
Imports: thirdpartypkg
# NAMESPACE
export(primary_function)
importFrom(thirdpartypkg, blackbox)
#' @name primary_function
#' @export
primary_function <- function(x, y, z){
# do something here
hidden(a = y, b = x, z = c)
}
# Unexported function
#' @name hidden
#' @importFrom thirdpartypkg blackbox
hidden <- function(a, b, c){
# do something here
# I CAN USE blackbox HERE AS IF IT WERE PART OF MY PACKAGE
# EVEN THOUGH I DIDN'T. CONSEQUENTLY, THE blackbox I IMPORTED
# ISN'T BEING USED.
thirdpartypkg::blackbox(a, c)
}
注意事项
那么哪种才是最好的使用方法呢?确实没有一个简单的答案。我会说备选方案3可能不是采取的方法。我可以告诉你,Wickham建议不要使用选项3(我一直在该框架下进行开发,而他建议我反对该选项)。
如果我们在选项1和选项2之间进行选择,我们必须考虑的因素是1)编写代码的效率,2)读取代码的效率和3)执行代码的效率。
在提高代码编写效率方面,通常使用
@importFrom thirdpartypkg blackbox
更容易,并且避免使用::
运算符。它只保存了一些按键。但是,这不利地影响了代码的可读性,因为现在尚不清楚blackbox
的来源。在读取代码的效率方面,最好省略
@importFrom
并使用thirdpartypkg::blackbox
。这使得blackbox
的来源很明显。关于执行代码的效率,最好使用
@importFrom
。调用thirdpartypkg::blackbox
比使用@importFrom
和调用blackbox
慢约0.1毫秒。那不是很多时间,所以可能不是很多考虑。但是,如果您的程序包使用了数百个::
构造,然后陷入循环或重采样过程,那么这些毫秒数可能会开始累加。最终,我认为我读过的最佳指南(并且我不知道在哪里)是,如果您要多次调用
blackbox
,那么值得使用@importFrom
。如果在一个包中只调用三到四次,请继续使用::
构造。关于r - R包:当我的导出函数未从其他包中显式调用函数,而子例程执行时,“import”的工作方式,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49427767/