r - 为什么/如何一些包在无名环境中定义它们的功能?
问题描述
在我的代码中,我需要检查函数是从哪个包定义的(在我的情况下是exprs()
:我需要它,Biobase
但结果被 覆盖rlang
)。
从这个 SO question,我想我可以简单地使用environmentName(environment(functionname))
。但是对于exprs
从Biobase
该表达式返回的空字符串:
environmentName(environment(exprs))
# [1] ""
检查结构后,environment(exprs)
我注意到它的.Generic
成员包含包名称作为属性:
environment(exprs)$.Generic
# [1] "exprs"
# attr(,"package")
# [1] "Biobase"
所以,现在我做了这个辅助函数:
pkgparent <- function(functionObj) {
functionEnv <- environment(functionObj)
envName <- environmentName(functionEnv)
if (envName!="")
return(envName) else
return(attr(functionEnv$.Generic,'package'))
}
它完成这项工作并正确返回函数的包名称(如果已加载),例如:
pkgparent(exprs)
# Error in environment(functionObj) : object 'exprs' not found
library(Biobase)
pkgparent(exprs)
# [1] "Biobase"
library(rlang)
# The following object is masked from ‘package:Biobase’:
# exprs
pkgparent(exprs)
# [1] "rlang"
但我仍然想了解,对于某些包,它们的功能是在“未命名”环境中定义的,而其他包看起来像<environment: namespace:packagename>
.
解决方案
您在这里看到的是 S4 方法分派工作原理的一部分。实际上,.Generic
是 R 方法分派机制的一部分。
顺便说一句,rlang 包是一个红鲱鱼:这个问题出现纯粹是由于 Biobase 使用 S4。
但更一般地说,您的解析策略在其他情况下可能会失败,因为还有其他原因(尽管很少)为什么包可能会在单独的环境中定义函数。这样做的原因通常是在某个变量上定义一个闭包。
例如,通常不可能在命名空间级别修改包内定义的变量,因为命名空间在加载时会被锁定。有多种方法可以解决此问题。如果一个包需要一个有状态的函数,一个简单的方法是在一个环境中定义这个函数。例如,您可以定义一个counter
在每次调用时增加其计数的函数,如下所示:
counter = local({
current = 0L
function () {
current <<- current + 1L
current
}
})
local
定义包装函数的环境。
为了应对这种情况,您应该做的是遍历父环境,直到找到命名空间环境。但是有一个更简单的解决方案,因为 R 已经提供了一个函数来为给定环境查找命名空间环境(通过执行所述迭代):
pkgparent = function (fun) {
nsenv = topenv(environment(fun))
environmentName(nsenv)
}
推荐阅读
- d3.js - D3 为什么地图不都是沿着X轴的?
- python - 使用 PyCharm 以不同宽度显示数据
- typescript - 数组的多个过滤器 - 打字稿
- angular - Primeng 动态菜单项
- outlook - 在 Outlook“获取事件 API”中获取键“reminderMinutesBeforeStart”的无效值
- php - 为什么我在 php 中收到“未捕获的 GuzzleHttp\Exception\ClientException:客户端错误”?
- flutter - 根据用户语言更改字体系列
- javascript - jQuery - 单击时添加/删除类
- reporting-services - 自定义字体在订阅 PDF 输出 SSRS 中不起作用
- node.js - 如何使用 REST API [NodeJS] 在画面中上传文件