我有一个带有包装函数的预处理包,可以帮助用户使用继承。这些用户定义的类和方法无法存储到密封的包名称空间中,就像我使用顶级代码默认类和方法一样。分配定义的正确环境是什么?下面的解决方案似乎在某种程度上起作用,但我不太了解它。
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"...
})
}
答案 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.env
。 topenv()
从指定的参数开始,并跟踪每个环境的封闭环境,直到它到达.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()
。