我正在使用R包,其中有2个函数f1和f2(f2调用f1)
我希望覆盖函数f1。
由于R 2.15和包中命名空间的强制使用,如果我只是获取新函数,它确实可以在全局环境中使用(即在控制台中只调用f1(x)返回新结果)。但是,调用f2仍将使用打包的函数f1。 (因为命名空间修改了搜索路径,并按照here in the Writing R Extensions教程所解释的那样密封它) 用新的方法完全替换f1的正确方法是什么? (除了再次构建包装!)这在几种情况下都很有用。例如,如果包中存在您尚未开发的错误。或者,如果您不想在每天仍在开发过程中重新构建软件包。
我知道功能
assignInNamespace("f1",f1,ns="mypackage")
然而,帮助页面?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"))
这非常令人不安。搜索路径如何受到影响?
现在我正在做一些丑陋的事情,例如修改lockEnvironment
函数,以便library
不会锁定包名称空间,我可以在以后锁定它取代f1(这似乎不是一个好习惯)
基本上我有两个问题:
assignInNamespace
到底做了什么编辑:对这个问题感兴趣的人可能会发现this blog post非常有趣。
答案 0 :(得分:6)
这里有很多不同的案例。
如果这是其他人包裹中的错误
然后最好的做法是联系包维护者并说服他们修复它。这样每个人都可以得到修复,而不仅仅是你。
如果在开发自己的软件包时出现错误
然后,您需要找到一个易于重建包的工作流程。就像使用devtools
包并输入build(mypackage)
,或点击按钮(RStudio中的“Build& Reload”;建筑师中的“R CMD build”)。
如果您只想要对现有软件包采取不同的行为
如果它不是这样的bug,或者包维护者不能进行你想要的修复,那么你将必须维护自己的f1
副本。使用assignInNamespace
在现有包中覆盖它可以进行探索,但它有点笨拙,所以它不适合永久解决方案。
您最好的办法是创建自己的包,其中包含f1
和f2
的副本。这比听起来要省力,因为你可以定义f2 <- existingpackage::f2
。
回应评论:
如果你是独自一人,那么第二和第三种情况是有意义的,但是他们需要构建和安装在我的组织中很棘手的软件包,因为软件包部署在几十台计算机上,我需要root访问权来更新软件包。
因此,请获取现有软件包源的副本,应用您的修补程序,并将其托管在您的公司网络或github或Bitbucket上。然后可以通过
以编程方式安装更新的软件包install.packages("//some/network/path/mypackage_0.0-1.tar.gz", repos = NULL)
或
library(devtools)
install_github("mypackage", "mygithubusername")
由于安装只是一行代码,因此您可以轻松地将其推送到任意数量的计算机。您也不需要root访问权限 - 只需将软件包安装到不需要root访问权限即可写入的库文件夹中。 (请阅读Startup和.libPaths帮助页面,了解如何定义新库。)您需要对这些计算机进行网络访问,但我无法帮助您。与您的网络管理员或您的老板或任何可以获得您许可的人交谈。
答案 1 :(得分:1)
如果函数在包中没有显式绑定:
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'))