编写健壮R代码里面:命名空间,掩盖和使用``::操作编写健壮R代码里面:命名空间,掩盖和使用``::

2019-05-17 11:53发布

精简版

对于那些不想通过我的“案例”来读取,这是本质:

  1. 什么是最小化的新软件包打破现有代码的机会被推荐的方式,即让你写尽可能稳定的代码?
  2. 是什么使得命名空间机制时,最好使用的推荐方式

    一)只使用贡献包(说的只是一些[R分析项目)?

    B)对于开发自己的包?

  3. 如何最有效地避免相对于正规课程 (主要是冲突引用类在我的情况),因为竟然没有一个命名空间机制媲美::上课(AFAIU)?


将R宇宙的运作方式

这是什么,一直在我的脑海两年左右的返现唠叨,但我不觉得我已经来到了一个令人满意的解决方案。 另外,我觉得它越来越差。

我们看到不断增加的件数CRAN , github上 , R-锻造之类的,这简直是太棒了。

在这样一个分散的环境,这是很自然的代码库,构成了R(让我们说这是基础R贡献R,为简单起见)从理想的状态偏离相对于稳健性:人们遵循不同的惯例,有S3,S4 ,S4引用类等东西不能作为“对齐”,因为他们将是如果有一个“ 中央结算实例 ”,强迫约定。 没关系。

问题

鉴于上述情况,它可以是很难用R编写健壮的代码。 不是你需要将在基地R.对于你最终会装载了不少贡献包某些项目的一切。

恕我直言,在这方面最大的问题是命名空间概念放在R来使用的方式,R允许写一个特定的功能/方法的名称,没有明确要求它的命名空间(即foonamespace::foo )。

所以为了简单起见,这就是大家都在做。 但这样一来,名字冲突,断码而无需重写/重构你的代码只是一个时间问题(或装载不同的包的数量)。

在最好的情况,你就会知道哪些现有功能被屏蔽/由新加入的包超载。 在最坏的情况,你会不知道,直到你的代码休息。

一对夫妇的例子:

  • 尝试加载RMySQL和RSQLite在同一时间,他们不走非常好
  • 也RMongo将覆盖的某些功能RMySQL
  • 预测掩盖了很多东西相对于ARIMA相关的功能
  • R.utils甚至掩盖了base::parse程序

(我不记得这功能特别是造成问题,但我愿意,如果有兴趣再次查找)

出人意料的是,这似乎并没有理会很多程序员在那里。 我试图加息几次,在R-devel的 ,没有显著无济于事。

使用的缺点::操作

  1. 使用::操作可能显著伤害在某些情况下效率多米尼克Samperi 指出 。
  2. 开发你自己的包,你甚至不能使用::操作在整个自己的代码作为你的代码是没有真正的包还没有,因此有还没有命名空间呢。 因此,我将不得不开始坚持到foo路,构建,测试,然后回去改变一切namespace::foo 。 并不是的。

可能的解决方案,以避免这些问题

  1. 重新分配从各包中的每个功能到遵循一定的命名约定的变量,例如namespace..foo为了避免与相关联的低效率namespace::foo (I概述一次这里 )。 优点:它的工作原理。 缺点:它的笨拙和您双击使用的内存。
  2. 发展你的包时, 模拟一个命名空间。 AFAIU,这是不是真的有可能,至少我被告知所以当时 。
  3. 强制要求使用namespace::foo 。 恕我直言,这将是最好的事情。 当然,我们会失去一些扩展简单,但随后再次将R宇宙只是没有简单了(至少它不是在早期的00一样简单)。

而关于(正规)班是什么?

除了上述方面, ::方式工作得很好的函数/方法。 但是,我们的类定义?

拿包TIMEDATE与它的类timeDate 。 说一个包走来其中也有一类timeDate 。 我不明白我怎么能明确指出我想类的新实例timeDate从两个包。

像这样将无法工作:

new(timeDate::timeDate)
new("timeDate::timeDate")
new("timeDate", ns="timeDate")

这可以是一个巨大的问题,因为越来越多的人转而到OOP风格为他们的R程序包,从而导致大量的类定义的。 如果一种方法来明确处理类定义的命名空间,我非常感谢指针!

结论

尽管这是一个有点冗长,我希望我能点出核心问题/问题,我也可以在这里提高大家的认识。

我认为devtools和mvbutils确实有可能是值得推广的一些方法,但我敢肯定有更多的话要说。

Answer 1:

伟大的问题。

验证

编写健壮,稳定,生产就绪R代码里面是很难的。 你说:“奇怪的是,这似乎并没有理会很多程序员在那里”。 这是因为,至多r程序员不写产品代码。 他们本是一次性的学术/科研任务。 我会认真质疑声称,R是容易投产任何编码的技能。 除了我的岗位上搜索/查找你已经挂机制,我也写了关于危险后警告 。 建议将有助于降低您的生产代码的复杂性。

提示编写健壮/生产R代码里面

  1. 避免使用使用进口depends和青睐套餐包。 与塞到进口依赖性的软件包仅完全可以放心使用。 如果你绝对必须使用员工所依赖的包,然后通过电子邮件发送你打电话后立即笔者install.packages()

这是我告诉笔者:“嗨作者,我是XYZ包的粉丝,我想提出一个要求你能不能从Depends中移动ABC和DEF对进口产品在未来的更新我不是你的包添加到? 。我自己包的进口,直到出现这种情况有R 2.14强制命名空间,每个包,来自R核心的原则是,包应尽量“好公民”如果我有加载A依赖包,它增加了一个显著的负担:我每次我走在一个新的程序包的相关时间来检查是否存在冲突。随着进口,包是免费的副作用。我明白,你可能会被这样破坏其他人的包。我认为它的正确的事情证明进口产品的承诺,并从长远来看,这将有助于人们产生更强大的R代码里面。”

  1. 使用importFrom。 不要一整包添加到进口,只添加您需要的特定功能。 我做到这一点与Roxygen2函数文档和roxygenize(),它自动地产生NAMESPACE文件。 通过这种方式,你可以导入具有在冲突并不是你真正需要使用的功能冲突的两个包。 这是乏味? 只有等到它成为一种习惯。 其优点是:可以快速识别所有的第三方依赖。 这有助于...

  2. 不要盲目的升级软件包。 阅读更新行由行,并考虑更新将如何影响你自己的包的稳定性。 在大多数情况下,更新不碰你实际使用的功能。

  3. 避免S4类。 我正在做一些挥手这里。 我觉得S4是复杂的,它需要足够的脑力应对搜索上R的功能方面你是否真的需要这些功能OO /查找机制? 管理状态=管理的复杂性 - 让使用Python或Java =)

  4. 编写单元测试。 使用testthat包。

  5. 每当你[R CMD建立/测试你的包,解析输出,并查找注意,信息,警告。 此外,身体用自己的眼睛进行扫描。 还有的创建步骤,指出冲突,但没有附上WARN,等它的一部分。

  6. 到第三方软件包的呼叫后立即加入断言和不变量。 换句话说,不要完全相信什么别人给你。 探测结果一点点, stop()如果结果是出乎意料的。 你不必去疯狂 - 挑选意味着有效/高可信度的结果的一个或两个断言。

我想有更多的,但这已经成为肌肉记忆,现在=)如果有更多的涉及到我,我会增加。



Answer 2:

我对此采取:

摘要:灵活性是要付出代价的。 我愿意付出这样的代价。

1)我根本不使用会使那样的问题包。 如果我真的,真的需要从包在我自己包的功能,我用的是importFrom()在我的NAMESPACE文件。 在任何情况下,如果我有麻烦了包,我联系包的作者。 问题是,在他们的身边,不属于R的。

2)我从来没有使用::里面我自己的代码。 通过仅出口由我包的用户所需要的功能,我可以保持我自己的命名空间中的功能,而不会在冲突。 未导出的函数不会隐藏具有相同名称的功能,要么,所以这是一个双赢。

对环境,命名空间和喜欢究竟是如何工作的一个很好的指导,你在这里找到: http://blog.obeautifulcode.com/R/How-R-Searches-And-Finds-Stuff/

这绝对是一个不可不看为大家写包和喜欢。 你看了之后,你就会意识到,使用::在你的包的代码是没有必要的。



文章来源: Writing robust R code: namespaces, masking and using the `::` operator