包中使用的setClass和setMethod包装器:什么是正确的赋值环境?

时间:2015-10-25 07:52:10

标签: r s4

我有一个带有包装函数的预处理包,可以帮助用户使用继承。这些用户定义的类和方法无法存储到密封的包名称空间中,就像我使用顶级代码默认类和方法一样。分配定义的正确环境是什么?下面的解决方案似乎在某种程度上起作用,但我不太了解它。

setpreprocessor <- function(classname, operation, mode="numeric"){

setClass(classname, contains="PreprocessorClass", 
where=topenv(parent.frame()), prototype=prototype(objectname=classname,  
objectoperation=operation))

setMethod("transformdata", where=topenv(parent.frame()), signature(object = 
classname), function(object, dataobject) {

...code here uses arguments "operation" and "mode"...
})
}

1 个答案:

答案 0 :(得分:2)

这是一个更完整的示例,其中包含一些格式以使代码结构更加明显

setClass("PreprocessorClass")

setGeneric("transformdata",
           function(object, dataobject) standardGeneric("transformdata"))

setpreprocessor <- function(classname, operation, mode="numeric") {

    setClass(classname, contains="PreprocessorClass", 
             where=topenv(parent.frame()),
             prototype=prototype(objectname=classname,  
               objectoperation=operation))

    setMethod("transformdata", signature(object = classname),
              where=topenv(parent.frame()),
              function(object, dataobject) {
                  ## code that uses 'operation', 'mode'
                  list(operation, mode)
              })
} 

parent.frame()函数的环境(不是函数定义的环境)。

几乎所有环境都有一个封闭的环境,通常是环境本身定义的环境;见?parent.envtopenv()从指定的参数开始,并跟踪每个环境的封闭环境,直到它到达.GlobalEnv或包名称空间。

因此,如果您的代码在PkgA包中,用户加载了包,然后从全局环境(命令提示符)调用setpreprocessor("Foo", "bar")parent.frame()将返回.GlobalEnv,如会topenv()。你会看到

> ls(all=TTRUE)
[1] ".__C__Foo" ".__T__transformdata:PkgA"

是在全局环境中创建的类和方法定义。

另一方面,如果用户在包中的函数中使用setpreprocessor()topenv(parent.frame())将最终在(密封的)包命名空间中。由于包命名空间是密封的,因此无法创建类或方法定义。

另一种方法是提供可以缓存类和方法定义的环境

.PreprocessorCache <- new.env()

setClass("PreprocessorClass")
## ...

然后使用

where=.PreprocessorCache

在类和方法定义中。然后可以交互式或在包代码中调用setpreprocessor()