为什么在R中,相比于R中的print(),message()是更好的选择?


80

我希望知道为什么message()print()打印诊断消息时更好的选择。

例如,该print()函数是打印R对象(如)的更好选择'iris',而message()当我们要连接字符串(例如message("a", "b")比短)时则更好print(paste0("a", "b"))

但是,我认为比上面列出的简单差异更多。我已经阅读了这两种方法的文档

但是,它们似乎不像我对问题的希望那样丰富。

如果有人让我们知道在哪种情况下message()比更好print(),为什么呢,我将不胜感激。


1
@MartinMorgan,我大体上同意这一点,但message()也暗示了一个“消息”,这就是suppressMessages()捕获的内容。 suppressMessages()不要抑制纯stderr输出,例如suppressMessages(cat("hello\n", file=stderr()))仍然显示hello在控制台中。
HenrikB '16

@HenrikB stopwarningmessage所有的信号条件,这是什么使他们抓住/抑制,能够tryCatch(message("hello"), message=force); cat(file=stderr())如果意图表示诊断状况,则表示样式较差(并且无效,如您的示例所示!)。
马丁·摩根

Answers:


139

TL; DR

为S3对象cat()创建print.*()函数时应使用。对于其他所有内容,message()除非程序状态有问题,否则应使用。例如,可恢复的严重错误给出warning()与显示停止错误的用法stop()

目标

这篇文章的目的是提供有关程序包开发人员可以访问的不同输出选项以及如何构造可能在新对象上或基于字符串的输出的反馈。

R输出概述

传统的输出函数是:

  1. print()
  2. cat()
  3. message()
  4. warning()
  5. stop()

现在,前两个函数(print()cat())将其输出发送到stdout标准输出。最后三个函数(message()warning()stop())将其输出发送到stderr或标准错误。也就是说,将类似命令的结果输出lm()发送到一个文件,将错误输出(如果存在)发送到一个完全独立的文件。对于用户体验而言,这尤其重要,因为诊断程序不会使结果的输出混乱到日志文件中,从而可以快速查找错误。

为用户和外部程序包设计

现在,以上内容在I / O思维方式中进行了更多的框架化,而不一定是面向用户的框架集。因此,让我们在日常R用户的背景下为其提供一些动力。特别是通过使用3-5或stderr功能,可以抑制其输出,而无需通过sink()或修改控制台文本capture.output()。抑制通常进来的形式suppressWarnings()suppressMessages()suppressPackageStartupMessages(),等等。因此,用户仅面临面向结果的输出。如果您打算允许用户灵活地通过knitrrmarkdownSweave创建动态文档时关闭基于文本的输出,那么这尤其重要。

特别是,knitr提供块选项,如error = Fmessage = Fwarning = F。这样可以减少文档中命令所伴随的文本。此外,这可以防止需要使用results = "hide"禁用所有输出的选项。

输出细节

打印()

首先,我们有一个老歌,但一个好东西print()。此功能有一些严重的限制。其中之一是缺乏术语的嵌入级联。第二个可能是更严重的事实是,每个输出之前都带有[x]实际内容周围的引号。在x这种情况下指的是正在打印的元件数目。这对于调试目的很有帮助,但除此之外,它没有任何作用。

例如

print("Hello!")

[1] "Hello!"

对于串联,我们依赖与以下paste()功能同步工作的功能print()

print(paste("Hello","World!"))

[1] "Hello World!"

另外,也可以使用paste0(...)函数代替,paste(...)以避免默认使用的参数所控制的space元素之间。(又名没有空格的串联)paste()sep = " "

例如

print(paste0("Hello","World!"))

[1] "HelloWorld!"

print(paste("Hello","World!", sep = ""))

[1] "HelloWorld!"

猫()

另一方面,cat()解决所有这些批评。最值得注意的是,该sep=" "的参数paste()的功能是建立在允许一个跳跃写入paste()cat()。但是,该cat()功能的唯一缺点是您必须通过\n在行末尾附加新行或fill = TRUE(使用默认打印宽度)。

例如

cat("Hello!\n")
Hello!

cat("Hello","World!\n")
Hello World!

cat("Hello","World!\n", sep = "")
HelloWorld!

因此,cat()在设计print.*()S3方法时应该使用它。

信息()

message()功能是一步比甚至更好cat()!输出之所以与传统的纯文本截然不同,是因为它指向stderr而不是stdout。例如,他们将颜色从标准的黑色输出更改为红色的输出,以引起用户的注意。

讯息输出

此外,您还具有内置paste0()功能。

message("Hello ","World!") # Note the space after Hello
"Hello World!"

此外,message()提供了可以与tryCatch()

例如

 tryCatch(message("hello\n"), message=function(e){cat("goodbye\n")})
 goodbye

警告()

warning()功能不是随便使用的东西。警告功能与消息功能的区别主要在于,在其前面加上了一行("Warning message:"),并且其状态被认为是有问题的。

警告输出

杂项:由于示例检查和警告通常被视为“错误”,因此在试图将程序包上载到CRAN时随意使用该功能可能会无意中触发心碎。

停()

最后但并非最不重要的是,我们有stop()。通过完全取消手头的任务并将控制权交还给用户,可以将警告提高到一个新的水平。此外,它具有最严重的前缀,"Error:"并添加了术语。

错误输出


设计打印时message("hello world")cat("hello world", sep="\n")S3方法有什么区别?
antonio

1
@antonio:message()将带有红色文本,另一个则没有。现在,如果您将变量添加到cat,例如cat("hello world", "antonio", sep="\n"),差异将是一行,hello world而另一行是antonio。但是,message()将所有内容保持在同一行。
没穿衣服的2016年

1
感谢您的大力回应。我正在寻找类似的东西,但我的问题被标记为“懒惰”:stackoverflow.com/questions/36065232/…–
汉堡


1
@WaldirLeoncio“诊断”输出是正在打印的内容,例如“级别信息”。不幸的是,该概念不存在message()cat()。我看了看是否有对R成熟的日志界面,是大多数系统今天的情况下(例如SLF4J API的Java),还有就是futile.logger -在CRAN
David Tonhofer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.