【问题标题】:How to let print() pass arguments to a user defined print method in R?如何让 print() 将参数传递给 R 中用户定义的打印方法?
【发布时间】:2015-08-06 12:45:39
【问题描述】:

我在 R 中定义了一个需要自己的打印方法的 S3 类。当我创建这些对象的列表并打印它时,R 对列表的每个元素使用我的打印方法,因为它应该这样做。

我想对 print 方法实际显示多少有所控制。因此,我的类的 print 方法需要一些额外的参数。但是,在打印对象列表时,我还没有找到利用这些参数的方法。

为了更清楚地说明这一点,我举一个例子。以下代码定义了test 类的两个对象,一个包含对象的列表和该类的打印方法:

obj1 <- list(a = 3, b = 2)
class(obj1) <- "test"
obj2 <- list(a = 1, b = 5)
class(obj2) <- "test"
obj_list <- list(obj1, obj2)

print.test <- function(x, show_b = FALSE, ...) {
  cat("a is", x$a, "\n")
  if (show_b) cat("b is", x$b, "\n")
}

打印单个对象按预期工作:

print(obj1)
## a is 3 
print(obj2, show_b = TRUE)
## a is 1 
## b is 5

当我打印obj_list时,我的打印方法用于打印列表中的每个对象:

print(obj_list)
## [[1]]
## a is 3 
## 
## [[2]]
## a is 1 

但我希望能够告诉print() 在这种情况下也显示b。以下(有点天真......)代码不会产生预期的结果:

print(obj_list, show_b = TRUE)
## [[1]]
## a is 3 
## 
## [[2]]
## a is 1

是否可以打印obj_list 并同时将参数show_b = TRUE 传递给print.test()?怎么样?

【问题讨论】:

  • 看起来print.default 忽略了...。 "...: further arguments to be passed to or from other methods. They are ignored in this function." Printing a list` 以print.default 结尾。所以你必须想办法绕过它。
  • 认为问题是obj_list 不属于test,它只是一个list。您可以尝试 class(obj_list) &lt;- c("test", "list") 并在 print.test 检查对象是否继承自 list 并采取相应措施。
  • 谢谢@Josh。按照您的建议,我为列表定义了自己的打印方法。这有效(因此我将其发布为答案),但我对解决方案有点不舒服。当然,这意味着任何列表都将使用我的方法打印,而不是来自 base R 的print.default()。而且我更倾向于信任来自 base R 的函数而不是我自己的函数......
  • @user2706569:你说得对,让列表有类test 可以用来解决问题。但这不是我想做的。该类定义了单个对象,而不是这些对象的列表。由于可以从 R 中的任何内容构建列表,因此仍然可以将 obj_list 放入列表并打印该列表。旧问题再次出现。

标签: r


【解决方案1】:

按照 Josh 的建议,我找到了一种避免在打印列表时调用 print.default() 的方法。我只是为列表编写了一个打印方法,因为似乎没有一个作为基本 R 的一部分存在:

print.list <- function(x, ...) {

  list_names <- names(x)
  if (is.null(list_names)) list_names <- rep("", length(x))

  print_listelement <- function(i) {
    if (list_names[i]=="") {
      cat("[[",i,"]]\n", sep="")
    } else {
      cat("$", list_names[i], "\n", sep="")
    }
    print(x[[i]], ...)
    cat("\n")
  }

  invisible(lapply(seq_along(x), print_listelement))

}

相关部分是当打印列表中的对象时,... 被传递给print。所以现在,回到问题中的示例,打印test 对象列表与show_b =TRUE 一起使用:

print(obj_list, show_b = TRUE)
## [[1]]
## a is 3 
## b is 2 
## 
## [[2]]
## a is 1 
## b is 5 

但是,我对自己定义 print.list 有点不舒服。它可能不如列表的内置打印机制那样工作。

【讨论】:

  • 如果您只想打印完全包含test 对象的列表,您可以让您的print.list 函数仅测试列表中的所有元素是否为test;如果他们使用你的方法;如果不只是调用print.default(x, ...) 回退到默认方法。
  • 是的,你是对的。这会更安全,因为除了那些专门由 test 对象构建的列表之外,我不会乱打印其他列表。如果您将此作为答案发布,我会接受...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-15
  • 1970-01-01
  • 2014-06-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多