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

setClass and setMethod wrappers used in a package: What is the correct assignment environment?

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

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"...
})
}

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

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() 将 return .GlobalEnvtopenv()。你会看到

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

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

另一方面,如果用户在包中的函数中使用了 setpreprocessor(),则 topenv(parent.frame()) 将在(密封的)包命名空间中结束。因为包命名空间是密封的,所以不可能创建 class 或方法定义。

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

.PreprocessorCache <- new.env()

setClass("PreprocessorClass")
## ...

然后使用

where=.PreprocessorCache

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