R:从包中覆盖函数的正确方法是什么?

Roc*_*nce 19 namespaces r package assign

我正在使用R包,其中有2个函数f1和f2(f2调用f1)
我希望覆盖函数f1.

由于R 2.15和包中命名空间的强制使用,如果我只是获取新函数,它确实可以在全局环境中使用(即在控制台中只调用f1(x)返回新结果).但是,调用f2仍将使用打包的函数f1.(因为命名空间修改了搜索路径,并按照"写入R扩展"教程中的说明对其进行了封装)
将f1替换为新命令的正确方法是什么?(除了再次构建包装!)这在几种情况下都很有用.例如,如果包中存在您尚未开发的错误.或者,如果您不想在日常开发过程中重新构建软件包.

我知道功能

assignInNamespace("f1",f1,ns="mypackage")
Run Code Online (Sandbox Code Playgroud)

但是,帮助页面?assignInNamespace有点令人讨厌,并且似乎不鼓励人们在不提供更多信息的情况下使用它,我在官方CRAN教程中找不到任何最佳实践建议.并在调用此函数后:

# Any of these 2 calls return the new function
mypackage::f1 
getFromNamespace(x = "f1", envir = as.environment("package:mypackage"))

# while this one still returns the old packaged version
getFunction(name = "f1", where = as.environment("package:mypackage")) 
Run Code Online (Sandbox Code Playgroud)

这非常令人不安.搜索路径如何受到影响?

现在我正在做一些丑陋的事情,比如修改lockEnvironment函数,这样library就不会锁定包命名空间,一旦我替换了f1,我可以在以后锁定它(这似乎不是一个好习惯)

所以基本上我有两个问题:

  1. assignInNamespace在包命名空间(应该被锁定)的情况下究竟做了什么
  2. 有什么好的做法?

非常感谢您在那里分享您的经验.

编辑:对此问题感兴趣的人可能会发现此博客文章非常有趣.

Ric*_*ton 7

这里有很多不同的案例.

如果它是别人的包中的错误
那么最好的做法是联系包维护者并说服他们修复它.这样每个人都能得到修复,而不仅仅是你.

如果在开发自己的软件包时出现问题,
那么您需要找到一个易于重建软件包的工作流程.就像使用devtools包和键入build(mypackage),或单击按钮(RStudio中的"Build&Reload"; Architect中的"R CMD build").

如果你只是想要对现有包有不同的行为
如果它不是这样的bug,或者包维护者不能进行你想要的修复,那么你将不得不维护自己的副本f1.使用assignInNamespace在现有包中覆盖它可以进行探索,但它有点hacky所以它不适合永久解决方案.

你最好的选择是创建自己的包含f1和的副本f2.这比听起来要少,因为你可以定义f2 <- existingpackage::f2.


回应评论:

第二种和第三种情况是有意义的,如果你是独自一人,但他们需要构建和安装在我的组织的情况下很棘手的软件包,因为软件包部署在几十台计算机上,我需要root访问权来更新软件包.

因此,请获取现有软件包源的副本,应用您的修补程序,并将其托管在您的公司网络或github或Bitbucket上.然后可以通过编程方式安装更新的包

install.packages("//some/network/path/mypackage_0.0-1.tar.gz", repos = NULL)
Run Code Online (Sandbox Code Playgroud)

要么

library(devtools)
install_github("mypackage", "mygithubusername")
Run Code Online (Sandbox Code Playgroud)

由于安装只是一行代码,因此您可以轻松地将其推送到任意数量的机器.您也不需要root访问权限 - 只需将软件包安装到不需要root访问权限即可写入的库文件夹中.(阅读Startup.libPaths帮助页面,了解如何定义新库.)您需要对这些计算机进行网络访问,但我无法帮助您.与您的网络管理员或您的老板或任何可以获得您许可的人交谈.

  • 同意所有这些要点,但如果你有时间,这一切都有效.**第一种情况**确实是最佳做法,但我需要先为我修复它,因为包装所有者在CRAN中修复它可能需要数周时间.**第二种和第三种情况**如果你是独自一人有意义,但是他们需要构建和安装软件包,这对我的组织来说是棘手的,因为软件包被部署在几十台计算机上,我需要root访问权来更新软件包.不幸的是,我认为R不适合那些匆忙的人. (2认同)

Dav*_*vic 7

如果函数在包中没有显式绑定:

rlang::env_unlock(env = asNamespace('mypackage'))
rlang::env_binding_unlock(env = asNamespace('mypackage'))
assign('f1', f1, envir = asNamespace('mypackage'))
rlang::env_binding_lock(env = asNamespace('mypackage'))
rlang::env_lock(asNamespace('mypackage'))
Run Code Online (Sandbox Code Playgroud)