studiodio org itam for r r-faq

org - ¿Cómo y cuándo debería usar on.exit?



r studiodio (1)

on.exit llama al código cuando sale una función, pero ¿cómo y cuándo debería usarla?


La ventaja de on.exit es que se llama cuando sale la función, independientemente de si se produjo un error . Esto significa que su uso principal es para limpiar después de un comportamiento arriesgado. Riesgo, en este contexto, generalmente significa acceder a recursos fuera de R (que, en consecuencia, no se puede garantizar que funcione). Los ejemplos comunes incluyen la conexión a bases de datos o archivos (donde la conexión debe cerrarse cuando finaliza, incluso si hubo un error), o guardar un diagrama en un archivo (donde el dispositivo gráfico debe cerrarse después).

También puede usar on.exit para on.exit de bajo riesgo con un efecto secundario, como establecer un directorio de trabajo.

Paquetes que hacen uso de on.exit

El paquete withr contiene muchas funciones with_* que cambian una configuración, ejecutan código y luego cambian la configuración. Estas funciones también aparecen en el paquete devtools .

Se encuentra una sintaxis alternativa en el paquete later donde defer es un envoltorio de conveniencia para on.exit , y las funciones scope_* funcionan como las funciones with_* en los paquetes mencionados anteriormente.

Conexiones de base

En este ejemplo, sqlite_get_query conecta a una base de datos sqlite, lo que garantiza que la conexión siempre se cierre después de que se haya ejecutado la consulta. La base de datos de cookies requiere que tengas instalado Firefox en tu máquina, y es posible que debas ajustar la ruta para encontrar el archivo de cookies.

library(RSQLite) sqlite_get_query <- function(db, sql) { conn <- dbConnect(RSQLite::SQLite(), db) on.exit(dbDisconnect(conn)) dbGetQuery(conn, sql) } cookies <- dir( file.path(Sys.getenv("APPDATA"), "Mozilla", "Firefox"), recursive = TRUE, pattern = "cookies.sqlite$", full.names = TRUE )[1] sqlite_get_query( cookies, "SELECT `baseDomain`, `name`, `value` FROM moz_cookies LIMIT 20" )

Conexiones de archivos

En este ejemplo, read_chars ajusta readChars , asegurando que la conexión al archivo esté siempre cerrada después de que la lectura haya finalizado.

read_chars <- function(file_name) { conn <- file(file_name, "r") on.exit(close(conn)) readChar(conn, file.info(file_name)$size) } tmp <- tempfile() cat(letters, file = tmp, sep = "") read_chars(tmp)

Archivos temporales

El siguiente ejemplo adaptado de CodeDepends usa un archivo temporal para guardar el historial de la sesión. Este archivo temporal no es necesario una vez que la función retorna, por lo que se elimina.

history_lines <- function() { f <- tempfile() on.exit(unlink(f)) savehistory(f) readLines(f, encoding = "UTF-8") }

Guardar gráficos base

En este ejemplo, my_plot es una función que crea una gráfica usando gráficos base. save_base_plot acepta una función y un archivo para guardarlo, usando on.exit para garantizar que el dispositivo gráfico esté siempre cerrado.

my_plot <- function() { with(cars, plot(speed, dist)) } save_base_plot <- function(plot_fn, file) { png(file) on.exit(dev.off()) plot_fn() } save_base_plot(my_plot, "testcars.png")

Establecer opciones de gráficos base temporalmente

En este ejemplo, plot_with_big_margins llama a plot , anulando el plot_with_big_margins global de on.exit de on.exit , usando on.exit para restablecerlo una vez que se completa el trazado.

plot_with_big_margins <- function(...) { old_pars <- par(mar = c(10, 9, 9, 7)) on.exit(par(old_pars)) plot(...) } plot_with_big_margins(with(cars, speed, dist))

withr / devtools equivalente: with_par

Establecer opciones globales temporalmente

En este ejemplo, create_data_frame es una función que crea un data.frame . create_data_frame asegura que el objeto creado no contenga factores explícitos.

create_data_frame <- function(){ op <- options(stringsAsFactors = FALSE) on.exit(options(op)) data.frame(x=1:10) }

withr / devtools equivalente: with_par
later equivalente: scope_options

Otros ejemplos

  • Configuración del directorio de trabajo ( withr::with_dir , later::scope_dir )
  • Configuración de componentes locales ( withr::with_locale )
  • Establecer variables de entorno ( withr::with_envvars , later::scope_env_var )
  • Configuración de las rutas de la biblioteca ( withr::with_libpaths )
  • Redirigir la salida con un fregadero
  • withr::with_package temporalmente un paquete ( withr::with_package , withr::with_namespace )