¿Por qué message () es una mejor opción que print () en R para escribir un paquete?

82

Espero saber por qué message()es una mejor opción que print()cuando se trata de imprimir mensajes de diagnóstico.

Por ejemplo, la print()función es una mejor opción para imprimir un objeto R como 'iris', mientras que, message()es mejor cuando queremos concatenar cadenas, por ejemplo, message("a", "b")es más corto que print(paste0("a", "b")).

Sin embargo, creo que hay más diferencias que las simples enumeradas anteriormente. He leído la documentación de ambos métodos.

pero, parece que no son tan informativos como esperaba para mi pregunta.

Agradecería que alguien nos diga en qué caso message()es mejor print()y por qué.

Kim
fuente
1
@MartinMorgan, estoy mayormente de acuerdo con esto, pero message()también señala un "mensaje", que es lo que suppressMessages()capta. suppressMessages()no suprima la salida stderr pura, por ejemplo, suppressMessages(cat("hello\n", file=stderr()))todavía se muestra helloen la consola.
HenrikB
@HenrikB stop, warning, messagetodas las condiciones de la señal, que es lo que los hace capturas / suprimir-capaz tryCatch(message("hello"), message=force); cat(file=stderr())es un estilo deficiente (e ineficaz, como lo ilustra su ejemplo) si la intención es señalar una condición de diagnóstico.
Martin Morgan

Respuestas:

146

TL; DR

Debería utilizarlo cat()al crear print.*()funciones para objetos S3. Para todo lo demás, debe usar a message()menos que el estado del programa sea problemático. p. ej., error incorrecto que es recuperable da warning()vs. mostrar usos de error de detención stop().

Objetivo

El objetivo de esta publicación es proporcionar comentarios sobre las diferentes opciones de salida a las que tiene acceso un desarrollador de paquetes y cómo se debe estructurar la salida que está potencialmente en un nuevo objeto o basada en cadenas.

Descripción general de la salida R

Las funciones de salida tradicionales son:

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

Ahora, las dos primeras funciones ( print()y cat()) envían su salida a stdoutla salida estándar. Las tres últimas funciones ( message(), warning()y stop()) envían su producción a stderro el error estándar. Es decir, la salida del resultado de un comando como lm()se envía a un archivo y la salida de error, si existe, se envía a un archivo completamente separado. Esto es particularmente importante para la experiencia del usuario, ya que los diagnósticos no saturan la salida de los resultados en archivos de registro y los errores están disponibles para buscar rápidamente.

Diseño para usuarios y paquetes externos

Ahora, lo anterior se enmarca más en una mentalidad de E / S y no necesariamente en un conjunto de marcos orientado al usuario. Entonces, proporcionemos algo de motivación para ello en el contexto de un usuario de R cotidiano. En particular, al usar 3-5 o las stderrfunciones, su salida se puede suprimir sin modificar el texto de la consola a través de sink()o capture.output(). La supresión normalmente viene en forma de suppressWarnings(), suppressMessages(), suppressPackageStartupMessages(), y así sucesivamente. Por lo tanto, los usuarios solo se enfrentan a la salida orientada a resultados. Esto es particularmente importante si planea permitir a los usuarios la flexibilidad de desactivar la salida basada en texto al crear documentos dinámicos a través de knitr , rmarkdown o Sweave .

En particular, knitrofrece opciones trozo tales como error = F, message = F, y warning = F. Esto permite la reducción del texto que acompaña a un comando en el documento. Además, esto evita la necesidad de usar la results = "hide"opción que deshabilitaría todas las salidas.

Detalles de la salida

impresión()

Primero, tenemos un viejo pero bueno, print(). Esta función tiene algunas limitaciones importantes. Uno de ellos es la falta de concatenación de términos incorporada. El segundo, y probablemente más grave, es el hecho de que cada salida va precedida [x]de citas en torno al contenido real. En xeste caso, se refiere al número de elemento que se está imprimiendo. Esto es útil para propósitos de depuración, pero fuera de eso no sirve para nada.

p.ej

print("Hello!")

[1] "Hello!"

Para la concatenación, confiamos en que la paste()función funcione en sincronía con print():

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

[1] "Hello World!"

Alternativamente, se puede usar la paste0(...)función en lugar de paste(...)para evitar el uso predeterminado de spaceentre elementos gobernados por paste()el sep = " "parámetro de. (también conocido como concatenación sin espacios)

p.ej

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

[1] "HelloWorld!"

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

[1] "HelloWorld!"

gato()

Por otro lado, cat()aborda todas estas críticas. Lo más notable es que el sep=" "parámetro de la paste()funcionalidad está integrado, lo que permite omitir la escritura paste()dentro cat(). Sin embargo, el cat()único inconveniente de la función es que tienes que forzar nuevas líneas a través del \napéndice al final o fill = TRUE(usa el ancho de impresión predeterminado).

p.ej

cat("Hello!\n")
Hello!

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

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

Es por esta misma razón por la que debe utilizarlo cat()al diseñar un print.*()método S3.

mensaje()

¡La message()función es un paso mejor que incluso cat()! La razón por la que la salida es distinta del texto sin formato tradicional al que se dirige en stderrlugar de stdout. Por ejemplo, cambiaron el color de salida en negro estándar a salida en rojo para llamar la atención de los usuarios.

Salida de mensaje

Además, tiene la paste0()funcionalidad incorporada.

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

Además, message()proporciona un estado de error que se puede utilizar contryCatch()

p.ej

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

advertencia()

La warning()función no es algo para usar de forma casual. La función de advertencia se diferencia de la función de mensaje principalmente por tener una línea prefijada ( "Warning message:") y su estado se considera problemático.

salida de advertencia

Misc: El uso casual de una función puede desencadenar inadvertidamente una angustia al intentar cargar el paquete en CRAN debido a que las comprobaciones y advertencias de ejemplo normalmente se tratan como "errores".

detener()

Por último, pero no menos importante, tenemos stop(). Esto lleva las advertencias al siguiente nivel al eliminar por completo la tarea en cuestión y devolver el control al usuario. Además, tiene el prefijo más serio con el término "Error:"agregado.

Salida de error

sin abrigo
fuente
¿Cuál es la diferencia entre message("hello world")y cat("hello world", sep="\n")al diseñar una impresión. * Método S3?
antonio
1
@antonio: message()tendrá texto en rojo y el otro no. Ahora, si agrega una variable a cat, por ejemplo cat("hello world", "antonio", sep="\n"), la diferencia será una línea con hello worldy otra con antonio. Sin embargo, message()mantendrá todo en la misma línea.
abrigo
1
Gracias por la gran respuesta. Estaba buscando algo similar, pero mi pregunta estaba etiquetada como "perezosa": stackoverflow.com/questions/36065232/…
burger
1
¿Qué pasa con write stackoverflow.com/questions/1109017/…
sjd
1
@WaldirLeoncio La salida de "diagnóstico" es lo que se está imprimiendo, por ejemplo, "a nivel de información". Desafortunadamente, ese concepto no existe con message()o cat(). Miré a si existe una interfaz de registro madura para R como es el caso de la mayoría de los sistemas de hoy en día (por ejemplo, la slf4j API para Java), y no es : futile.logger - En CRAN .
David Tonhofer