on.exit
вызывает код при выходе из функции, но как и когда я должен его использовать?
Как и когда следует использовать on.exit?
Ответ 1
Преимущество on.exit
заключается в том, что он вызывается, когда функция выходит, независимо от того, была ли выбрана ошибка. Это означает, что его основное назначение - очистка после рискованного поведения. В этом контексте рискованный подход обычно означает доступ к ресурсам за пределами R (что, следовательно, не может быть гарантировано работать). Обычные примеры включают подключение к базам данных или файлу (когда соединение должно быть закрыто, когда вы закончили, даже если произошла ошибка) или сохранение графика в файл (где графическое устройство должно быть закрыто впоследствии).
Вы также можете использовать on.exit
для поведения с низким уровнем риска с побочным эффектом, например, для установки рабочего каталога.
Пакеты, которые используют on.exit
Пакет withr
содержит множество функций with_*
, которые меняют настройку, запускают некоторый код, а затем изменяют настройку. Эти функции также отображаются в пакете devtools
.
Альтернативный синтаксис находится в пакете later
, где defer
- это удобная обертка для on.exit
и scope_*
функции работают как функции with_*
в ранее упомянутых пакетах.
Соединения с базой данных
В этом примере sqlite_get_query
подключается к базе данных sqlite, обеспечивая
что соединение всегда закрывается после выполнения запроса. cookies
для базы данных требуется, чтобы на вашем компьютере был установлен firefox, и вы можете
необходимо настроить путь для поиска файла cookie.
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"
)
Подключение файлов
В этом примере read_chars
обертывает readChars
, гарантируя, что соединение
к файлу всегда закрывается после завершения чтения.
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)
Временные файлы
В следующем примере, адаптированном из CodeDepends, используется временный файл для сохранения истории сеанса. Этот временный файл не нужен, как только функция вернется, чтобы она была удалена.
history_lines <- function()
{
f <- tempfile()
on.exit(unlink(f))
savehistory(f)
readLines(f, encoding = "UTF-8")
}
Сохранение базовой графики
В этом примере my_plot
- это функция, которая создает сюжет с использованием базы
графика. save_base_plot
принимает функцию и файл, чтобы сохранить ее, используя
on.exit
, чтобы графическое устройство было всегда закрыто.
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")
Временное определение параметров базовой графики
В этом примере plot_with_big_margins
вызывает plot
, переопределяя глобальный mar
gin par
ameter, используя on.exit
до reset после завершения графика.
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
эквивалент: with_par
Временное изменение глобальных параметров
В этом примере create_data_frame
- это функция, которая создает data.frame
. create_data_frame
гарантирует, что созданный объект не содержит явных факторов.
create_data_frame <- function(){
op <- options(stringsAsFactors = FALSE)
on.exit(options(op))
data.frame(x=1:10)
}
withr
/devtools
эквивалент: with_options
later
эквивалент: scope_options
Другие примеры
- Настройка рабочего каталога (
withr::with_dir
,later::scope_dir
) - Установка языковых компонентов (
withr::with_locale
) - Настройка переменных среды (
withr::with_envvars
,later::scope_env_var
) - Настройка путей библиотеки (
withr::with_libpaths
) - Перенаправление вывода с раковиной
- Временная загрузка пакета