我正在为另一个包中定义的泛型创建S3方法。泛型的较早方法会产生一些控制台输出,这些输出不会作为函数返回值的一部分返回,而只会输出到控制台。我想捕获该输出以用于我自己的方法。
我尝试在capture.output()
上使用NextMethod()
,但这只会导致一个奇怪的错误:
foo <- function(x, ...) UseMethod("foo")
foo.bar <- function(x, ...) cat(x, "\n")
foo.baz <- function(x, ...) capture.output(NextMethod())
foo(structure(1, class = "bar"))
#> 1
foo(structure(1, class = c("baz", "bar")))
#> Error: 'function' is not a function, but of type 8
这是预期的行为,已知的限制还是错误?通过快速搜索,我找不到与该错误匹配的任何内容。 如何在另一个S3方法中捕获下一个S3方法的输出?
答案 0 :(得分:2)
这是...“预期行为”。我之所以这样说,是因为我认为这在技术上是正确的,但是用户可能无法期望它。如果您不关心为什么会发生这种情况,而只是想看看如何解决它,请跳到标题“修复”,因为以下有关错误的解释有些涉及。
'function' is not a function, but of type 8
是什么意思? type 8
表示类型8 SEXP
。来自Section one of the R Internals Manual:
R用户认为是变量或对象的是符号,它们是 绑定到一个值。该值可以视为SEXP(a 指针)或其指向的结构,即SEXPREC ...
当前正在使用SEXPTYPEs 0:10和13:25。...
没有SEXPTYPE描述
...
3个CLOSXP封盖
...
8个BUILTINSXP内置函数
NextMethod()
期望CLOSXP
,而不是BUILTINSXP
。如果我们查看do_nextmethod()
的{{3}}(在第717行附近),这是NextMethod()
的C函数
SEXP attribute_hidden do_nextmethod(SEXP call, SEXP op, SEXP args, SEXP env)
{
// Some code omitted
if (TYPEOF(s) != CLOSXP){ /* R_LookupMethod looked for a function */
if (s == R_UnboundValue)
error(_("no calling generic was found: was a method called directly?"));
else
errorcall(R_NilValue,
_("'function' is not a function, but of type %d"),
TYPEOF(s));
}
那为什么在这里发生呢?这是棘手的地方。我相信这是因为通过将NextMethod()
通过capture.output()
,它是使用内置的eval()
来调用的(请参见builtins()
)。
那么我们该如何处理呢?继续阅读...
我们可以巧妙地使用sink()
,cat()
和tempfile()
模拟捕获输出:
foo.baz <- function(x, ...) {
# Create a temporary file to store the output
tmp <- tempfile("tmp.txt")
# start sink()
sink(tmp)
# call NextMethod() just for the purpose of capturing output
NextMethod()
# stop sink'ing
sink()
# store the output in an R object
y <- readLines(tmp)
# here we'll cat() the output to make sure it worked
cat("The output was:", y, "\n")
# destroy the temporary file
unlink(tmp)
# and call NextMethod for its actual execution
NextMethod()
}
foo(structure(1, class = c("baz", "bar")))
# 1
答案 1 :(得分:0)
我不确定您看到的内容是否已记录:文档?NextMethod
清楚地表明它不是常规功能,但我没有遵循所有详细信息来查看您的用法是否会被允许。
一种做自己想要的事的方法就是
foo.baz <- function(x, ...) {class(x) <- class(x)[-1]; capture.output(foo(x, ...))}
这假定该方法是从对泛型的调用中直接调用的;如果存在第三级,它将无法正常工作,并且foo.baz
本身是由NextMethod()
调用的。