从内部获取打包函数的属性

时间:2013-04-27 02:48:53

标签: r namespaces package environment attr

假设我们在R包中有这个功能。

prova <- function() {
  print(attr(prova, 'myattr'))
  print(myattr(prova))
  invisible(TRUE)
}
'myattr<-' <- function(x, value) {
  attr(x, 'myattr') <- value
  x
}
myattr <- function(x) attr(x, 'myattr')

所以,我安装包然后测试它。这是结果:

prova()
# NULL
# NULL
myattr(prova) <- 'ciao' # setting 'ciao' for 'myattr' attribute
prova()
# NULL
# NULL # Why NULL here ?
myattr(prova)
# [1] "ciao"
attr(prova, 'myattr')
# [1] "ciao"

问题是:如何从内部获取函数的属性?

在函数本身内部,我无法获得其属性,如示例所示。

我认为解决方案将是系列语言&#34;计算语言&#34; (match.call()[[1L]]substitute,环境和朋友)。我错了吗?

我认为这里的重点是这个函数在一个包中(因此,它有环境和命名空间),我需要它自己的属性,在包裹中,而不是在外面。

2 个答案:

答案 0 :(得分:0)

您可以将getenvir参数一起使用。

prova <- function() {

  print(attr(get("prova", envir=envir.prova), 'myattr'))
  print(myattr(prova))
  invisible(TRUE)
}

例如:

envir.prova <- environment()
prova()
# NULL
# NULL
myattr(prova) <- 'ciao' 
prova()
# [1] "ciao"
# [1] "ciao" 

其中envir.prova是一个变量,其值设置为定义prova的环境。
或者,您可以使用get(.. envir=parent.frame()),但这不太可靠,因为您必须跟踪调用,并确保在目标环境和调用环境之间使用相同名称的另一个对象。

评论中有关问题的更新:

关于使用parent.frame()与使用明确的环境名称:parent.frame,顾名思义,“向上一级”。通常,这正是你想去的地方,所以工作正常。然而,即使您的目标是在更高的环境中获取对象,R也会搜索调用堆栈,直到找到具有匹配名称的对象。很多时候,parent.frame()就好了。

HOWEVER 如果您在调用parent.frame()的位置与对象位于其中一个中间环境中 AND 之间存在多个调用,则存在另一个对象如果名称相同,则R将停在该中间环境并返回对象,该对象您要查找的对象。

因此,parent.frame()有一个参数n(默认为1),因此您可以告诉R开始在n级别搜索。

这是我所指的“保持跟踪”,开发人员必须注意其间的呼叫次数。解决这个问题的直接方法是在调用相关函数的每个函数中都有一个n参数,并将该值默认为1.然后对于envir参数,使用:{ {1}} get/assign/eval/etc

然后,如果您从(.. , envir=parent.frame(n=n) )致电Func2,(Func1Func1都有Func2参数),n正在呼叫Func2,您使用:

prova

正如你所看到的,它不是复杂的,但它是*乏味的*有时看起来像一个bug爬进去,这只是忘记携带n。

因此,我更喜欢使用带有环境名称的固定变量。

答案 1 :(得分:-1)

我找到的解决方案是:

myattr <- function(x) attr(x, 'myattr')

'myattr<-' <- function(x, value) {
  # check that x is a function (e.g. the prova function)
  # checks on value (e.g. also value is a function with a given precise signature)
  attr(x, 'myattr') <- value
  x
}

prova <- function(..., env = parent.frame()) {
  # get the current function object (in its environment)
  this <- eval(match.call()[[1L]], env)
  # print(eval(as.call(c(myattr, this)), env)) # alternative
  print(myattr(this))
  # print(attr(this, 'myattr')

  invisible(TRUE)
}   

我要感谢@RicardoSaporta提供有关跟踪电话跟踪的帮助和说明。

此解决方案在例如myattr(prova) <- function() TRUE嵌套在func1prova,而func2调用func1env调用prova。除非您没有正确更新其参数prova <- function(..., pos = 1L) { # get the current function object (in its environment) this <- eval(match.call()[[1L]], parent.frame(n = pos) print(myattr(this)) # ... } ...

为了完整性,按照@RicardoSaporta的建议,我略微修改了pos函数:

prova

这样,如果传入了正确的myfun1 <- function() { myattr(prova) <- function() print(FALSE) myfun2(n = 2) } myfun2 <- function(n) { prova(pos = n) } myfun1() # function() print(FALSE) # <environment: 0x22e8208> 参数,它也可以在嵌套时使用。

通过此修改,您可以更轻松地在功能{{1}}上设置属性的环境中消失。

{{1}}