Écrire des fonctions robustes avec stop() et warning()
Déclenchez des conditions personnalisées depuis vos propres fonctions.
Écrire des fonctions robustes avec stop() et warning() est une leçon R Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage R Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours R Academy comprend 4 leçons au total.
Pourquoi la validation des entrées est importante
Les fonctions défensives vérifient leurs entrées et échouent explicitement avec des erreurs informatives au lieu de produire silencieusement des résultats incorrects. Une fonction qui intercepte les mauvaises entrées à la frontière est bien plus facile à déboguer qu’une fonction qui propage des données incohérentes dans un pipeline.
# Without validation: wrong result, no error
bad_mean <- function(x) sum(x) / length(x)
bad_mean('hello') # no error, just NA
# With validation: clear error
good_mean <- function(x) {
if (!is.numeric(x)) stop('x must be numeric')
sum(x) / length(x)
}
tryCatch(good_mean('hello'), error = function(e) cat(e$message, '\n'))Messages d’erreur informatifs
Les erreurs génériques comme stop('bad input') sont difficiles à déboguer. Utilisez paste0() ou sprintf() dans stop() pour inclure la valeur réelle et le type attendu dans le message. Cela fait gagner du temps lors du suivi des erreurs dans les pipelines.
check_numeric <- function(x, arg_name = 'x') {
if (!is.numeric(x)) {
stop(sprintf(
"'%s' must be numeric, but got class '%s'",
arg_name, class(x)
))
}
}
tryCatch(check_numeric('abc', 'score'),
error = function(e) cat(e$message, '\n'))Valider la longueur et l’intervalle
Validations courantes : vérifier qu’un vecteur n’est pas vide (length(x) == 0), qu’un scalaire se trouve dans un intervalle donné ou qu’un tableau de données contient les colonnes attendues. Chaque vérification doit avoir son propre message d’erreur adapté.
validate_prob <- function(p) {
if (!is.numeric(p)) stop(paste0('p must be numeric, got: ', class(p)))
if (length(p) != 1) stop(paste0('p must be length 1, got: ', length(p)))
if (p < 0 || p > 1) stop(paste0('p must be in [0,1], got: ', p))
p
}
cat(validate_prob(0.7), '\n')
tryCatch(validate_prob(1.5), error = function(e) cat(e$message, '\n'))Utiliser warning() pour les problèmes non bloquants
Utilisez warning() lorsque la fonction peut tout de même renvoyer un résultat raisonnable, mais que l’appelant doit savoir qu’un événement inhabituel s’est produit, par exemple la conversion d’une valeur, l’imputation d’une valeur par défaut ou la détection d’une entrée à la limite.
clamp <- function(x, lo, hi) {
if (any(x < lo)) warning(paste0(sum(x < lo), ' value(s) below lo, clamped'))
if (any(x > hi)) warning(paste0(sum(x > hi), ' value(s) above hi, clamped'))
pmax(lo, pmin(hi, x))
}
result <- clamp(c(2, -5, 7, 100, 4), 0, 10)
cat('Result:', result, '\n')call. = FALSE dans stop()
Par défaut, stop() ajoute Error in funcname(...): au début du message. Transmettez call. = FALSE pour supprimer ce préfixe lorsque le contexte d’appel est évident ou lorsque la fonction est un utilitaire destiné à l’utilisateur.
# With call. = TRUE (default): shows calling function
f1 <- function(x) stop('bad input')
tryCatch(f1(1), error = function(e) cat(conditionMessage(e), '\n'))
# With call. = FALSE: cleaner message
f2 <- function(x) stop('bad input', call. = FALSE)
tryCatch(f2(1), error = function(e) cat(conditionMessage(e), '\n'))Classes de conditions personnalisées pour stop()
Créez une classe d’erreur personnalisée avec structure() afin que les appelants puissent intercepter uniquement les erreurs de votre fonction, sans intercepter toutes les erreurs. C’est la manière professionnelle d’écrire des erreurs au niveau d’un paquet.
value_error <- function(msg, call = sys.call(-1)) {
structure(
class = c('value_error', 'error', 'condition'),
list(message = msg, call = call)
)
}
check_positive <- function(x) {
if (x <= 0) stop(value_error(paste0('Expected positive, got: ', x)))
x
}
tryCatch(check_positive(-3),
value_error = function(e) cat('ValueError:', e$message, '\n'),
error = function(e) cat('Other error:', e$message, '\n'))Vérifier les colonnes d’un tableau de données
Lorsqu’une fonction attend un tableau de données, vérifiez que les colonnes requises existent avant de les utiliser. Utilisez %in% pour vérifier les noms de colonnes et setdiff() pour signaler les colonnes manquantes.
require_cols <- function(df, cols) {
missing <- setdiff(cols, names(df))
if (length(missing) > 0) {
stop(paste0('Missing columns: ', paste(missing, collapse = ', ')))
}
invisible(df)
}
df <- data.frame(x = 1:3, y = 4:6)
tryCatch(
require_cols(df, c('x', 'z', 'w')),
error = function(e) cat(e$message, '\n')
)stopifnot() pour des assertions concises
stopifnot(condition1, condition2, ...) génère une erreur si l’une des conditions vaut FALSE. C’est une manière concise d’affirmer les préconditions au début d’une fonction sans écrire plusieurs blocs if (!...) stop(...).
compute_area <- function(width, height) {
stopifnot(
is.numeric(width),
is.numeric(height),
width > 0,
height > 0
)
width * height
}
cat(compute_area(5, 3), '\n')
tryCatch(compute_area(-1, 3), error = function(e) cat(e$message, '\n'))stopifnot() nommé pour de meilleurs messages
Dans R 4.0+, les expressions nommées de stopifnot() remplacent le message généré automatiquement par votre description personnalisée. Utilisez le texte de l’expression comme nom afin de produire des échecs informatifs.
validate_age <- function(age) {
stopifnot(
'age must be numeric' = is.numeric(age),
'age must be positive' = age > 0,
'age must be under 150' = age < 150
)
invisible(age)
}
tryCatch(validate_age(-5), error = function(e) cat(e$message, '\n'))
tryCatch(validate_age('x'), error = function(e) cat(e$message, '\n'))Combiner validation et logique métier
Une fonction bien structurée sépare la validation de la logique. Validez au début, puis effectuez l’opération. La fonction est ainsi plus facile à lire et les erreurs sont détectées avant le début de tout calcul.
discount_price <- function(price, pct) {
if (!is.numeric(price) || price <= 0)
stop(paste0('price must be positive numeric, got: ', price))
if (!is.numeric(pct) || pct < 0 || pct > 100)
stop(paste0('pct must be in [0,100], got: ', pct))
if (pct > 50) warning('discount > 50% is unusual')
price * (1 - pct / 100)
}
cat(discount_price(100, 20), '\n')
cat(suppressWarnings(discount_price(100, 60)), '\n')tryCatch dans les fonctions utilitaires
Parfois, une fonction utilitaire doit gérer les erreurs en interne et renvoyer une valeur de remplacement plutôt que de les propager. Encapsulez la logique principale dans tryCatch() et renvoyez un indicateur convenu, comme NA ou NULL, en cas d’échec.
safe_log <- function(x) {
tryCatch({
if (!is.numeric(x)) stop('not numeric')
if (x <= 0) stop('must be positive')
log(x)
}, error = function(e) {
warning(paste0('safe_log failed for x=', x, ': ', e$message))
NA_real_
})
}
results <- sapply(list(10, -1, 'a', 100), safe_log)
cat(results, '\n')Vérification rapide
Que fait call. = FALSE lorsqu’il est transmis à stop() ?
Fonctions robustes : points essentiels
Points essentiels pour écrire des fonctions robustes :
- Validez les entrées au début ; échouez explicitement avec des messages
stop()informatifs - Incluez la valeur réelle dans les messages d’erreur :
paste0('Expected numeric, got: ', class(x)) - Utilisez
warning()pour les problèmes non bloquants lorsque le calcul peut continuer call. = FALSEsupprime le préfixe de la fonction appelante dans les messages d’erreurstopifnot()pour des assertions concises ; sa forme nommée pour des messages personnalisés (R 4.0+)- Les classes de conditions personnalisées permettent une interception sélective par les appelants
robust_divide <- function(x, y) {
stopifnot('x must be numeric' = is.numeric(x),
'y must be numeric' = is.numeric(y))
if (y == 0) stop('Division by zero', call. = FALSE)
if (abs(y) < 1e-10) warning('y is very small; result may be inaccurate')
x / y
}
cat(robust_divide(10, 2), '\n')
tryCatch(robust_divide(10, 0), error = function(e) cat(e$message, '\n'))Apprends R avec un tuteur IA — gratuit
Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.
- Cours
- 43
- Leçons
- 159
Questions Fréquemment Posées
La leçon « Écrire des fonctions robustes avec stop() et warning() » est-elle gratuite ?
Oui — le texte complet de « Écrire des fonctions robustes avec stop() et warning() » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours R Academy, passe à CoddyKit PRO. Le cours R Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Écrire des fonctions robustes avec stop() et warning() » ?
Déclenchez des conditions personnalisées depuis vos propres fonctions. Tu pratiques R Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer R Academy ?
Aucune expérience préalable n'est requise. R Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Écrire des fonctions robustes avec stop() et warning() » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon R Academy ?
Oui. Chaque leçon R Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Erreurs, avertissements et messages dans R
- tryCatch() pour récupérer les erreurs
- withCallingHandlers() et redémarrages
- Écrire des fonctions robustes avec stop() et warning()