简体   繁体   English

R包:当导出的函数没有显式调用其他包中的函数时,“导入”如何工作,但子例程却如此

[英]R Package: how “import” works when my exported function does not call explicitly a function from other packages, but a subroutine does

I am developing my first R package and there is something that it is not clear to me about Imports in the DESCRIPTION file. 我正在开发我的第一个R包,并且有一些东西我不清楚描述文件中的Imports I went through quite some guides that explain package structure but I do not find an answer to my question, so here is my situation. 我经历了一些解释包结构的指南,但我没有找到问题的答案,所以这是我的情况。

  • I define a function f that I will export, so its definition will have the proper @export roxygen comment on top. 我定义了一个我将导出的函数f ,因此它的定义将在顶部有正确的@export roxygen注释。
  • now, my function f calls a subroutine hidden , that I do not want to export. 现在,我的函数f调用一个hidden的子程序,我不想导出。 Function hidden uses other packages too, say package X . 函数hidden使用其他包,比如包X

Because the call to X is inside function hidden , there is no tag @import X in my function f . 因为对X的调用是hidden函数内部,所以函数f没有@import X标记。 Thus, I added package X to the Imports in my DESCRIPTION file, hoping to specify the relevant dependency there. 因此,我将包X添加到我的DESCRIPTION文件中的Imports ,希望在那里指定相关的依赖项。

When I use devtools::document() , however, the generated NAMESPACE does not contain an entry for X . 但是,当我使用devtools::document()时,生成的NAMESPACE不包含X的条目。 I can see why that happens: the parser just does not find the flag in the roxygen comment for f , and at runtime a call to f crashes because X is missing. 我可以看到为什么会发生这种情况:解析器在f的roxygen注释中找不到标志,并且在运行时调用f因为X丢失而崩溃。

Now, I can probably fix everything by specifying X in the import of f . 现在,我可以通过在导入f指定X来修复所有内容。 But why is the mechanism this tricky? 但为什么这个机制很棘手? Or, similarly, why my imports in DESCRIPTION do not match the ones in NAMESPACE? 或者,同样地,为什么我在DESCRIPTION中的导入与NAMESPACE中的导入不匹配?

My understanding is that there are three "correct" ways to do the import. 我的理解是有三种“正确”的方法来进行导入。 By "correct," I mean that they will pass CRAN checks and function properly. 通过“正确”,我的意思是他们将通过CRAN检查并正常运行。 Which option you choose is a matter of balancing various advantages and is largely subjective. 您选择哪个选项是平衡各种优势的问题,并且主要是主观的。

I'll review these options below using the terminology 我将使用术语查看以下这些选项

  • primary_function the function in your package that you wish to export primary_function您要导出的包中的函数
  • hidden the unexported function in your package used by primary_function hiddenprimary_function使用的包中未导出的函数
  • thirdpartypkg::blackbox , blackbox is an exported function from the thirdpartypkg package. thirdpartypkg::blackboxblackboxthirdpartypkg包中的导出函数。

Option 1 (no direct import / explicit function call) 选项1(没有直接导入/显式函数调用)

I think this is the most common approach. 我认为这是最常见的方法。 thirdpartypkg is declared in the DESCRIPTION file, but nothing is imported from thirdpartypkg in the NAMESPACE file. thirdpartypkg在DESCRIPTION文件中声明,但在NAMESPACE文件中没有从thirdpartypkg导入任何内容。 In this option, it is necessary to use the thirdpartypkg::blackbox construct to get the desired behavior. 在此选项中, 必须使用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)
}

Option 2 (direct import / no explicit function call) 选项2(直接导入/无显式函数调用)

In this option, you directly import the blackbox function. 在此选项中,您可以直接导入blackbox功能。 Having done so, it is no longer necessary to use thirdpartypkg::blackbox ; 完成后,不再需要使用thirdpartypkg::blackbox ; you may simply call blackbox as if it were a part of your package. 你可以简单地将blackbox称为你的包的一部分。 (Technically it is, you imported it to the namespace, so there's no need to reach to another namespace to get it) (从技术上讲,它是将它导入命名空间,因此不需要到达另一个命名空间来获取它)

# 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)
}

Option 3 (direct import / explicit function call) 选项3(直接导入/显式函数调用)

Your last option combines the the previous two options and imports blackbox into your namespace, but then uses the thirdpartypkg::blackbox construct to utilize it. 您的最后一个选项结合了前两个选项并将blackbox导入您的命名空间,但随后使用thirdpartypkg::blackbox构造来使用它。 This is "correct" in the sense that it works. 从它起作用的意义上说,这是“正确的”。 But it can be argued to be wasteful and redundant. 但它可以被认为是浪费和多余的。

The reason I say it is wasteful and redundant is that, having imported blackbox to your namespace, you're never using it. 我说这是浪费和多余的原因是,将blackbox导入您的命名空间后,您永远不会使用它。 Instead, you're using the blackbox in the thirdpartypkg namespace. 相反,您正在使用thirdpartypkg命名空间中的blackbox Essentially, blackbox now exists in two namespaces, but only one of them is ever being used. 从本质上讲, blackbox现在存在于两个名称空间中,但只使用其中一个名称空间。 Which begs the question of why make the copy at all. 这引出了为什么要制作副本的问题。

# 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)
}

Considerations 注意事项

So which is the best approach to use? 那么哪种方法最好用? There isn't really an easy answer to that. 对此并不是一个简单的答案。 I will say that Option 3 is probably not the approach to take. 我会说选项3可能不是采取的方法。 I can tell you that Wickham advises against Option 3 (I had been developing under that framework and he advised me against it). 我可以告诉你,Wickham建议反对备选方案3(我一直在该框架下开发,他建议我反对它)。

If we make the choice between Option 1 and Option 2, the considerations we have to make are 1) efficiency of writing code, 2) efficiency of reading code, and 3) efficiency of executing code. 如果我们在选项1和选项2之间做出选择,我们必须考虑的因素是:1)编写代码的效率,2)读取代码的效率,以及3)执行代码的效率。

When it comes to the efficiency of writing code, it's generally easier to @importFrom thirdpartypkg blackbox and avoid having to use the :: operator. 在编写代码的效率方面, @importFrom thirdpartypkg blackbox通常更容易,并且避免使用::运算符。 It just saves a few key strokes. 它只保存了几个击键。 This adversely affects readability of code, however, because now it isn't immediately apparent where blackbox comes from. 然而,这会对代码的可读性产生不利影响,因为现在blackbox来源并不是很明显。

When it comes to efficiency of reading code, it's superior to omit @importFrom and use thirdpartypkg::blackbox . 在读取代码的效率方面,它优于省略@importFrom并使用@importFrom thirdpartypkg::blackbox This makes it obvious where blackbox comes from. 这使得blackbox来自哪里显而易见。

When it comes to efficiency of executing code, it's better to @importFrom . 在执行代码的效率方面,最好是@importFrom Calling thirdpartypkg::blackbox is about 0.1 milliseconds slower than using @importFrom and calling blackbox . 调用thirdpartypkg::blackbox比使用@importFrom并调用blackbox慢约0.1毫秒。 That isn't a lot of time, so probably isn't much of a consideration. 这不是很多时间,所以可能不是很重要。 But if your package uses hundreds of :: constructs and then gets thrown into looping or resampling processes, those milliseconds can start to add up. 但是如果你的包使用了数百个:: constructs然后被抛入循环或重新采样过程,那么这些毫秒就可以开始加起来了。

Ultimately, I think the best guidance I've read (and I don't know where) is that if you are going to call blackbox more than a handful of times, it's worth using @importFrom . 最后,我认为我读过的最好的指导(我不知道在哪里)是,如果你打算多次打电话给blackbox ,那么值得使用@importFrom If you will only call it three or four times in a package, go ahead and use the :: construct. 如果您只在包中调用三到四次,请继续使用:: construct。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 相同的R函数在Global Env中用作函数/对象,从R包加载时不起作用 - Same R function works as function/object in Global Env, does not work when loaded from R package Import R function exported from package A into B by C package - Import R function exported from package A into B by C package 如何从Imports中列出的R包中覆盖导出的函数 - How to override exported function from R package listed in Imports 如何清除错误:对象 <some function> 不是&#39;名称空间导出: <some package> &#39;在构建我的R包时出现了什么? - How do I clear Error: object <some function> is not exported by 'namespace:<some package>' which shows up when building my R package? 使用其他包中的功能 - 何时使用 package::function? - Using functions from other packages - when to use package::function? 如何从 Rcpp 调用 R 函数(不应导出)? - How to call R function (which should not be exported) from Rcpp? R函数interSpline实际如何工作? - How does the R function interSpline actually works? 从 [包] 导入 [功能] 在 R - From [package] import [function] in R 在编写自己的R包时,我似乎无法正确导入其他包 - When writing my own R package, I can't seem to get other packages to import correctly 调试R中未由包导出的函数 - debugging a function in R that was not exported by a package
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM