包中使用的 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.env
。 topenv()
从指定的参数开始,跟踪每个环境的封闭环境,直到到达 .GlobalEnv 或包命名空间。
因此,如果您的代码位于包 PkgA 中,用户加载该包,然后从全局环境(命令提示符)调用 setpreprocessor("Foo", "bar")
,parent.frame()
将 return .GlobalEnv
,topenv()
。你会看到
> 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()
然后可以交互方式或在包代码中调用。
我有一个带有包装函数的预处理包,可以帮助用户使用继承。这些用户定义的 类 和方法不能存储到密封包命名空间,就像我对顶级代码默认 类 和方法所做的那样。将定义分配到的正确环境是什么?下面的解决方案似乎以某种方式起作用,但我不太了解它。
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.env
。 topenv()
从指定的参数开始,跟踪每个环境的封闭环境,直到到达 .GlobalEnv 或包命名空间。
因此,如果您的代码位于包 PkgA 中,用户加载该包,然后从全局环境(命令提示符)调用 setpreprocessor("Foo", "bar")
,parent.frame()
将 return .GlobalEnv
,topenv()
。你会看到
> 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()
然后可以交互方式或在包代码中调用。