Rap*_*ter 45 coding-style namespaces r package masking
对于那些不想阅读我的"案例"的人来说,这就是本质:
什么是在何时充分利用命名空间机制的推荐方法
a)只使用贡献包(比如在一些R分析项目中)?
b)关于开发自己的包裹?
如何最好地避免与正式类(在我的情况下主要是引用类)之间的冲突,因为甚至没有与::类(AFAIU)相当的命名空间机制?
这件事情在我脑海中唠叨了大约两年了,但我觉得我没有达到令人满意的解决方案.另外我觉得情况越来越糟.
我们看到CRAN,github,R-Forge等上的包装数量越来越多,这简直太棒了.
在这样一个分散的环境中,组成R的代码库(简单来说就是基础R和贡献R,为简单起见)自然会偏离理想状态而不是鲁棒性:人们遵循不同的约定,有S3,S4如果存在强制执行约定的" 中央清算实例 ",那么事情就不会像它们那样"一致" .没关系.
鉴于上述情况,使用R编写健壮的代码可能非常困难.并非您需要的所有东西都在基础R中.对于某些项目,您最终会加载相当多的贡献包.
恕我直言,这方面最大的问题是命名空间概念在R中使用的方式:R允许简单地写出某个函数/方法的名称而不明确要求它的命名空间(即foovs. namespace::foo).
所以为了简单起见,这就是每个人都在做的事情.但是这样,名称冲突,破坏代码以及重写/重构代码的需要只是时间问题(或者加载的不同包的数量).
充其量,您将了解新添加的包掩盖/重载哪些现有功能.在最坏的情况下,在您的代码中断之前,您将毫无头绪.
几个例子:
(我不记得哪些功能特别导致了这些问题,但如果有兴趣,我愿意再次查询)
令人惊讶的是,这似乎并没有困扰很多程序员.我试图在r-devel上多次提高兴趣,但没有显着的效果.
::运营商的缺点::Dominick Samperi 指出,使用操作员可能会在某些情况下严重影响效率.::在自己的代码中使用运算符,因为你的代码还没有真正的包,因此还没有命名空间.因此,我必须首先坚持foo方式,构建,测试,然后回到改变一切namespace::foo.并不是的.namespace..foo为了避免与之相关的低效率namespace::foo(我在此处概述了一次).优点:它的工作原理.缺点:它很笨拙,你使用的内存加倍.namespace::foo.恕我直言,这将是最好的事情.当然,我们会失去一些简单性,但是R宇宙再也不简单了(至少它不像00年代早期那么简单).除了上述方面之外,::方式对于功能/方法也很有效.但是类定义怎么样?
用它的类来包装timeDatetimeDate.说另一个包也有一个类timeDate.我没有看到我如何明确表示我想timeDate从两个包中的任何一个包中获得一个新的类实例.
这样的东西不起作用:
new(timeDate::timeDate)
new("timeDate::timeDate")
new("timeDate", ns="timeDate")
Run Code Online (Sandbox Code Playgroud)
这可能是一个巨大的问题,因为越来越多的人为他们的R包切换到OOP风格,导致许多类定义.如果有是一种方法,明确处理类定义的命名空间,我非常感谢指针!
虽然这有点冗长,但我希望我能够指出核心问题/问题,并且我可以在这里提高认识.
SFu*_*n28 32
很棒的问题.
编写健壮,稳定且生产就绪的R代码很难.你说:"令人惊讶的是,这似乎并没有打扰很多程序员." 那是因为大多数R程序员都没有编写生产代码.他们正在进行一次性的学术/研究任务.我会严重质疑任何声称R很容易投入生产的编码员的技能.除了我已经链接到的关于搜索/查找机制的帖子,我还写了一篇关于警告危险的帖子.这些建议有助于降低生产代码的复杂性.
install.packages(). 以下是我告诉作者的内容:"嗨作者,我是XYZ包的粉丝.我想提出请求.你可以在下次更新时将ABC和DEF从Depends移动到Imports吗?我无法将你的包添加到我自己的软件包的Imports直到这种情况发生.R 2.14为每个软件包强制执行NAMESPACE,来自R Core的一般信息是软件包应该尝试成为"好公民".如果我必须加载Depends软件包,它会增加一个重大负担:我必须在每次依赖新包时检查冲突.使用Imports,包没有副作用.我知道你可能会破坏其他人的包.我认为这是正确的做法展示对Imports的承诺,从长远来看,它将帮助人们生成更强大的R代码."
使用importFrom.不要将整个包添加到Imports,只添加您需要的那些特定功能.我用Roxygen2函数文档和roxygenize()自动生成NAMESPACE文件.通过这种方式,您可以导入两个冲突不存在于实际需要使用的函数中的包.这很乏味吗?直到它成为一种习惯.好处:您可以快速识别所有第三方依赖项.这有助于......
不要盲目升级包.逐行阅读更改日志,并考虑更新将如何影响您自己的软件包的稳定性.大多数情况下,更新不会触及您实际使用的功能.
避免S4课程.我在这里挥手.我发现S4很复杂,需要足够的脑力来处理R功能方面的搜索/查找机制.你真的需要这些OO功能吗?管理状态=管理复杂性 - 留给Python或Java =)
写单元测试.使用testthat包.
无论何时R CMD构建/测试您的包,解析输出并查找NOTE,INFO,WARNING.另外,用自己的眼睛进行物理扫描.构建步骤的一部分记录了冲突,但没有附加WARN等.
在调用第三方软件包后立即添加断言和不变量.换句话说,不要完全相信别人给你的东西.稍微探测一下结果,stop()如果结果是意外的.你不必发疯 - 选择一两个暗示有效/高可信度结果的断言.
我认为还有更多,但现在已成为肌肉记忆=)如果有更多的话,我会增加.
Jor*_*eys 15
我接受它:
总结:灵活性需要付出代价.我愿意支付这个价格.
1)我根本不使用导致这类问题的包.如果我真的需要在我自己的包中使用该包中的函数,我会importFrom()在我的NAMESPACE文件中使用.无论如何,如果我遇到包装问题,我会联系包裹作者.问题出在他们身边,而不是R's.
2)我从不::在自己的代码中使用.通过仅导出我的包的用户所需的函数,我可以将自己的函数保存在NAMESPACE中而不会遇到冲突.未导出的函数也不会隐藏具有相同名称的函数,因此这是双赢.
有关环境,命名空间等工作原理的详细指南,请访问:http: //blog.obeautifulcode.com/R/How-R-Searches-And-Finds-Stuff/
对于每个人都在编写包等等,这绝对是必读的.阅读完本文后,您将意识到::在包装代码中使用是没有必要的.