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
)