withCallingHandlers() и перезапуски
Используйте withCallingHandlers() для обработки условий за пределами локальной области.
«withCallingHandlers() и перезапуски» — бесплатный урок R Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения R Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс R Academy содержит 4 уроков всего.
tryCatch и withCallingHandlers
Ключевое различие: tryCatch() создаёт нелокальный выход — после перехвата условия управление покидает выражение и не возвращается в него. withCallingHandlers() сохраняет стек вызовов и может продолжить выполнение после обработки.
# tryCatch: execution does NOT continue after warning
tryCatch({
warning('first')
cat('This line is never reached\n')
}, warning = function(w) cat('tryCatch caught:', w$message, '\n'))withCallingHandlers сохраняет выполнение
При использовании withCallingHandlers() обработчик выполняется, но после выдачи условия выполнение продолжается (если сам обработчик не выдаёт ошибку и не вызывает механизм восстановления). Стек вызовов не раскручивается.
withCallingHandlers({
warning('first warning')
cat('Execution continues here\n')
warning('second warning')
cat('And here too\n')
}, warning = function(w) {
cat('Handler saw:', w$message, '\n')
invokeRestart('muffleWarning')
})Механизм восстановления muffleWarning
Вызов invokeRestart('muffleWarning') внутри обработчика предупреждения не даёт стандартному обработчику R вывести предупреждение. Без этого после выполнения Вашего обработчика R всё равно вывел бы предупреждение с помощью стандартного механизма.
# Without muffleWarning: warning still shows after handler
withCallingHandlers({
warning('test')
}, warning = function(w) {
cat('Handler ran\n')
# no muffleWarning: default handler still fires
})Механизм восстановления muffleMessage
Аналогично, invokeRestart('muffleMessage') внутри обработчика сообщения подавляет сообщение после того, как Ваш обработчик его обработает. Именно этот механизм лежит в основе suppressMessages().
withCallingHandlers({
message('Progress: 50%')
message('Progress: 100%')
}, message = function(m) {
cat('[LOG]', trimws(m$message), '\n')
invokeRestart('muffleMessage')
})Запись предупреждений без остановки выполнения
Практическое применение withCallingHandlers(): собирайте предупреждения в вектор журнала, позволяя коду завершить работу. tryCatch() остановился бы на первом предупреждении, а withCallingHandlers() соберёт их все.
warnings_log <- character(0)
result <- withCallingHandlers({
x <- log(-1)
y <- sqrt(-4)
c(x, y)
}, warning = function(w) {
warnings_log <<- c(warnings_log, w$message)
invokeRestart('muffleWarning')
})
cat('Warnings logged:', length(warnings_log), '\n')
cat(warnings_log, sep = '\n')Концепция invokeRestart()
Механизмы восстановления — это заранее определённые стратегии восстановления, которые код, выдающий условие, может предложить. invokeRestart(name) выбирает одну из этих стратегий. Встроенные механизмы включают 'muffleWarning' и 'muffleMessage'; собственные механизмы можно определить с помощью withRestarts().
# withRestarts() offers named recovery options
divide_safe <- function(x, y) {
withRestarts(
{
if (y == 0) stop('division by zero')
x / y
},
use_zero = function() 0,
use_na = function() NA
)
}
# A handler can pick a restart
withCallingHandlers(
divide_safe(10, 0),
error = function(e) invokeRestart('use_zero')
)Сочетание withCallingHandlers и tryCatch
Эти два средства можно вкладывать друг в друга: используйте снаружи withCallingHandlers(), чтобы записывать условия в журнал или подсчитывать их, а внутри — tryCatch(), чтобы возвращать резервное значение. Внешний обработчик первым видит условие.
n_warnings <- 0L
result <- withCallingHandlers(
tryCatch(log(-1), warning = function(w) -999),
warning = function(w) {
n_warnings <<- n_warnings + 1L
cat('Logged warning #', n_warnings, '\n')
}
)
cat('Result:', result, '\n')Пользовательские классы условий
Пользовательские классы условий можно создать, вызвав structure() для списка с классом c('myError', 'error', 'condition'). Обработчики сопоставляются по классу, поэтому пользовательские классы позволяют перехватывать определённые типы ошибок, не перехватывая все ошибки.
my_error <- function(msg, data = NULL) {
structure(
class = c('my_error', 'error', 'condition'),
list(message = msg, data = data)
)
}
tryCatch(
stop(my_error('custom error', data = 42)),
my_error = function(e) cat('Custom handler, data=', e$data, '\n'),
error = function(e) cat('Generic handler\n')
)Когда использовать withCallingHandlers
Используйте withCallingHandlers(), когда нужно наблюдать за условиями или записывать их в журнал, не останавливая выполнение. Используйте tryCatch(), когда нужно восстановиться после условия и вернуть альтернативное значение. Эти средства решают разные задачи.
# withCallingHandlers: observe all, continue
withCallingHandlers(
for (x in c(4, -1, 9, -4)) cat(suppressWarnings(sqrt(x)), ''),
warning = function(w) cat('[warn]', '')
)
cat('\n')Цепочка выдачи условий
Когда выдаётся условие, R поднимается по стеку вызовов в поисках обработчиков. Обработчики withCallingHandlers() выполняются в динамическом контексте (стек вызовов сохраняется). Обработчики tryCatch() выполняются после раскрутки стека — исходный контекст уже недоступен.
# Demonstrate: withCallingHandlers handler can see full stack
f <- function() {
withCallingHandlers(
g(),
warning = function(w) {
cat('Caught in f, stack length:', sys.nframe(), '\n')
invokeRestart('muffleWarning')
}
)
}
g <- function() warning('from g')
f()Реализация suppressWarnings()
suppressWarnings(expr) по сути является withCallingHandlers(expr, warning = function(w) invokeRestart('muffleWarning')). Понимание этого позволяет создавать собственные варианты, подавляющие только определённые типы предупреждений.
# Suppress only NaN warnings, not others
suppress_nan_warn <- function(expr) {
withCallingHandlers(expr, warning = function(w) {
if (grepl('NaN', conditionMessage(w)))
invokeRestart('muffleWarning')
})
}
suppress_nan_warn(log(-1)) # NaN warning suppressed
tryCatch(
suppress_nan_warn(warning('other issue')),
warning = function(w) cat('Other warning kept:', w$message, '\n')
)Быстрая проверка
В чём заключается главное различие между withCallingHandlers() и tryCatch()?
Механизмы восстановления: главное
Главное о withCallingHandlers и механизмах восстановления:
withCallingHandlers()= локальный обработчик, стек вызовов сохраняется, выполнение может продолжатьсяtryCatch()= нелокальный выход, стек раскручивается, можно вернуть альтернативное значениеinvokeRestart('muffleWarning')подавляет стандартный вывод предупрежденияinvokeRestart('muffleMessage')подавляет стандартный вывод сообщения- Используйте
withCallingHandlers(), чтобы собирать или записывать в журнал все условия, не останавливая выполнение - Пользовательские классы условий позволяют выборочно перехватывать определённые типы ошибок
log_vec <- character(0)
withCallingHandlers({
message('start')
warning('low memory')
message('end')
}, message = function(m) {
log_vec <<- c(log_vec, paste('MSG:', trimws(m$message)))
invokeRestart('muffleMessage')
}, warning = function(w) {
log_vec <<- c(log_vec, paste('WARN:', w$message))
invokeRestart('muffleWarning')
})
cat(log_vec, sep = '\n')Часто задаваемые вопросы
Урок «withCallingHandlers() и перезапуски» бесплатный?
Да — полный текст урока «withCallingHandlers() и перезапуски» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс R Academy, подпишись на CoddyKit PRO. Курс R Academy содержит 4 уроков всего.
Чему я научусь в уроке «withCallingHandlers() и перезапуски»?
Используйте withCallingHandlers() для обработки условий за пределами локальной области. Ты практикуешь R Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать R Academy?
Предыдущий опыт не требуется. R Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «withCallingHandlers() и перезапуски»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке R Academy?
Да. Каждый урок R Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Ошибки, предупреждения и сообщения в R
- tryCatch() для восстановления после ошибок
- withCallingHandlers() и перезапуски
- Надёжные функции с stop() и warning()