Чому message () є кращим вибором, ніж print () у R для написання пакету?


82

Я сподіваюся знати, чому 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

@HenrikB stop, warning, messageвсі умови сигналу, який , що робить їх улов / пригнічує-стан tryCatch(message("hello"), message=force); cat(file=stderr())поганий стиль (і неефективний, як це показує ваш приклад!), якщо метою є сигналізація про стан діагностики.
Мартін Морган,

Відповіді:


146

TL; DR

Ви повинні використовувати, cat()створюючи print.*()функції для об'єктів S3. Для всього іншого слід використовувати, message()якщо стан програми не є проблематичним. наприклад, погана помилка, що підлягає відновленню, дає warning()проти використання помилка зупинки використання stop().

Мета

Мета цього допису - надати відгук про різні варіанти виводу, до яких має доступ розробник пакунків, і про те, як слід структурувати вихід, який потенційно може бути на новому об'єкті або базуватися на рядках.

R Огляд вихідних даних

Традиційними функціями виводу є:

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

Тепер перші дві функції ( print()і cat()) надсилають свої вихідні дані до stdoutабо стандартного виводу. Три останні функції ( message(),, warning()і stop()) надсилають свої вихідні дані stderrабо стандартну помилку. Тобто результат, виведений з команди типу lm(), надсилається в один файл, а вивід помилки - якщо він існує - надсилається в абсолютно окремий файл. Це особливо важливо для взаємодії з користувачем, оскільки тоді діагностика не заповнює результати результатів у файлах журналів, а помилки доступні для швидкого пошуку.

Проектування для користувачів та зовнішніх пакетів

Тепер вищезазначене оформлено більше у спосіб миттєвого введення-виведення, і не обов’язково для набору кадрів, що відповідає користувачеві. Отже, давайте подамо мотивацію для цього в контексті повсякденного користувача R. Зокрема, використовуючи 3-5 або stderrфункції, їх вихід можна придушити, не заважаючи тексту консолі за допомогою sink()або capture.output(). Придушення зазвичай приходить у вигляді suppressWarnings(), suppressMessages(), suppressPackageStartupMessages()і так далі. Таким чином, користувачі стикаються лише з результатами, які стикаються з результатами. Це особливо важливо, якщо ви плануєте дозволити користувачам гнучко вимикати текстовий вихід при створенні динамічних документів за допомогою в'язального пристрою , rmarkdown або Sweave .

Зокрема, knitrпропонує варіанти порцій , наприклад error = F, message = Fі warning = F. Це дозволяє зменшити текст, що супроводжує команду в документі. Крім того, це запобігає необхідності використання results = "hide"опції, яка відключала б усі вихідні дані.

Особливості виробництва

print ()

До перших, у нас є дідок , але хороший, 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()буде тримати все на одній лінії.
пальто

1
Дякую за чудовий відгук. Я шукав щось подібне, але моє запитання було позначено як "ліниве": stackoverflow.com/questions/36065232/…
бургер

1
sjd

1
@WaldirLeoncio "Діагностичний" результат - це те, що друкується, наприклад "на рівні інформації". На жаль, цього поняття не існує з message()або cat(). Я подивився, чи існує зрілий інтерфейс реєстрації для R, як це відбувається у більшості систем сьогодні (наприклад, API slf4j для Java), і є : futile.logger - у CRAN .
Девід Тонхофер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.