【问题标题】:Why is message() a better choice than print() in R for writing a package?为什么 message() 比 R 中的 print() 更适合编写包?
【发布时间】:2016-08-10 12:04:55
【问题描述】:

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

例如,print() 函数是打印 R 对象(例如 'iris')的更好选择,而message() 则更好用于连接字符串,例如message("a", "b")print(paste0("a", "b")) 短。

但是,我认为除了上面列出的那些简单的区别之外,还有更多的区别。我已经阅读了这两种方法的文档

但是,它们似乎没有我对我的问题所希望的那么丰富。

如果有人告诉我们在哪种情况下message()print() 更好,我将不胜感激,以及为什么。

【问题讨论】:

  • @MartinMorgan,我基本同意这一点,但message() 也表示“消息”,这是suppressMessages() 捕获的。 suppressMessages() 不要抑制纯标准错误输出,例如suppressMessages(cat("hello\n", file=stderr())) 仍会在控制台中显示 hello
  • @HenrikB stop, warning, message 所有信号条件,这使得它们能够捕获/抑制 tryCatch(message("hello"), message=force); cat(file=stderr()) 的风格很差(如您的示例所示,无效!)如果意图发出诊断条件的信号。

标签: r


【解决方案1】:

TL;DR

在为 S3 对象创建 print.*() 函数时,您应该使用 cat()。对于其他一切,您应该使用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(...) 来避免在paste()sep = " " 参数控制的元素之间默认使用空格。 (也就是没有空格的连接)

例如

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

[1] "HelloWorld!"

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

[1] "HelloWorld!"

猫()

另一方面,cat() 解决了所有这些批评。最值得注意的是,paste() 功能的sep=" " 参数是内置的,允许在cat() 中跳过写入paste()。但是,cat() 函数的唯一缺点是您必须通过附加在末尾的\nfill = TRUE(使用默认打印宽度)来强制换行。

例如

cat("Hello!\n")
Hello!

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

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

正是出于这个原因,您在设计print.*() S3 方法时应该使用cat()

消息()

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:"

【讨论】:

  • 在设计print.* S3方法时message("hello world")cat("hello world", sep="\n")有什么区别?
  • @antonio: message() 将有红色文本,而另一个则不会。现在,如果您将变量添加到 cat,例如cat("hello world", "antonio", sep="\n"),区别是一行与hello world,另一行与antonio。不过,message() 会将所有内容保持在同一行。
  • 感谢您的好评。我正在寻找类似的东西,但我的问题被标记为“懒惰”:stackoverflow.com/questions/36065232/…
  • @WaldirLeoncio “诊断”输出是正在打印的内容,例如“级别信息”。不幸的是,message()cat() 不存在这个概念。我查看了 R 是否有一个成熟的日志接口,就像当今大多数系统一样(例如 Java 的 slf4j API),futile.logger - At CRAN
猜你喜欢
  • 2011-04-03
  • 2015-04-08
  • 1970-01-01
  • 1970-01-01
  • 2011-07-26
  • 1970-01-01
  • 1970-01-01
  • 2012-02-17
相关资源
最近更新 更多