R:从包中覆盖函数的正确方法是什么? [英] R: what's the proper way to overwrite a function from a package?

查看:264
本文介绍了R:从包中覆盖函数的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using a R package, in which there are 2 functions f1 and f2 (with f2 calling f1)
I wish to overwrite function f1.

由于R 2.15和软件包中名称空间的强制性使用,如果我仅提供新功能,则它确实可以在全局环境中使用(即,仅在控制台中调用f1(x)即可返回新结果).但是,调用f2仍将使用打包的函数f1. (因为名称空间修改了搜索路径,并按照此处为Writing R扩展教程)
用新的f1完全替代f1的正确方法是什么? (除了再次构建程序包!)在某些情况下这很有用.例如,如果您尚未开发的程序包中存在错误.或者,如果您不想在仍在开发中时每天重新构建软件包.

Since R 2.15 and the mandatory usage of namespace in packages, if I just source the new function, it is indeed available in the global environement (ie. just calling f1(x) in the console returns the new result). However, calling f2 will still use the packaged function f1. (Because the namespace modifies the search path, and seals it as explained here in the Writing R Extensions tutorial)
What is the proper way to completely replace f1 with the new one? (apart from building again the package!) This can be useful in several situations. For instance if there is a bug in a package that you have not developed. Or if you don't want to re-build your packages everyday while they are still under development.

我了解功能

assignInNamespace("f1",f1,ns="mypackage")

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

However, the help page ?assignInNamespace is a bit enignmatic and seems to discourage people from using it without giving more information, and I couldn't find any best practice recommendations on the official CRAN tutorial. and after calling this function:

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

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

This is very disturbing. How is the search path affected?

就目前而言,我正在做一些丑陋的事情,例如修改lockEnvironment函数,以使library不会锁定包名称空间,并且在替换f1后,我可以在以后的阶段将其锁定(这似乎确实是不是一个好习惯)

For now I am doing some ugly things such as modifying the lockEnvironment function so that library doesn't lock the package namespace, and I can lock it at a later stage once I have replaced f1 (which seems really not a good practice)

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

So basically I have 2 questions:

  1. 在包名称空间(应该是锁定的)的情况下,assignInNamespace到底能做什么?
  2. 有哪些好的做法?
  1. what does exactly do assignInNamespace in the case of a package namespace (which is supposed to be locked)
  2. What are the good practices?

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

many thanks for sharing your experience there.

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

people interested in this question might find this blog post extremely interesting.

推荐答案

这里有很多不同的情况.

There are lots of different cases here.

如果这是其他人的软件包中的错误
然后,最佳实践是与软件包维护者联系并说服他们对其进行修复.这样,每个人都可以得到修复,而不仅仅是您.

If it's a bug in someone else's package
Then the best practice is to contact the package maintainer and persuade them to fix it. That way everyone gets the fix, not just you.

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

If it's a bug while developing your own package
Then you need to find a workflow where rebuilding packages is easy. Like using the devtools package and typing build(mypackage), or clicking a button ("Build & Reload" in RStudio; "R CMD build" in Architect).

如果您只想要与现有软件包不同的行为
如果不是这样的错误,或者包维护人员无法进行所需的修复,那么您将必须维护自己的f1副本.使用assignInNamespace在现有程序包中覆盖它可以进行探索,但是它有点hacky,因此它并不适合永久解决方案.

If you just want different behaviour to an existing package
If it isn't a bug as such, or the package maintainer won't make the fix that you want, then you'll have to maintain you own copy of f1. Using assignInNamespace to override it in the existing package is OK for exploring, but it's a bit hacky so it isn't really suitable for a permanent solution.

您最好的选择是创建一个包含f1f2副本的包.因为您可以定义f2 <- existingpackage::f2.

Your best bet is to create your own package containing copies of f1 and f2. This is less effort than it sounds, since you can just define f2 <- existingpackage::f2.

针对评论:

如果您是一个人,则第二和第三种情况很有意义,但是它们需要构建和安装软件包,对于我的组织而言,这很棘手,因为这些软件包已部署在数十台计算机上,并且我需要root访问权限才能更新这些软件包.

Second and third cases makes sense if you are alone but they require to build and install the packages which is tricky in the case of my organisation as the packages are deployed on dozens of computer and I need root access to update the packages.

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

So take a copy of the existing package source, apply your patch, and host it on your company network or github or Bitbucket. Then the updated package can be installed programmatically via

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

library(devtools)
install_github("mypackage", "mygithubusername")

由于安装仅是一行代码,因此您可以轻松地将其推送到任意数量的计算机上.您也不需要root用户访问权限-只需将软件包安装到不需要root访问权限即可写入的库文件夹中. (阅读启动

Since the installation is just a line of code, you can easily push it to as many machines as you like. You don't need root access either - just install the package to a library folder that doesn't require root access to write to. (Read the Startup and .libPaths help pages for how to define a new library.) You'll need network access to those machines, but I can't help you with that. Speak to your network administrator or your boss or whoever can get you permission.

这篇关于R:从包中覆盖函数的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆