J'ai lu quelques autres SO questions sur tryCatch
et cuzzins, ainsi que la documentation:
mais je ne comprends toujours pas.
J'exécute une boucle et je souhaite passer à next
si l'un des types d'erreurs se produit:
for (i in 1:39487) {
# EXCEPTION HANDLING
this.could.go.wrong <- tryCatch(
attemptsomething(),
error=function(e) next
)
so.could.this <- tryCatch(
doesthisfail(),
error=function(e) next
)
catch.all.errors <- function() { this.could.go.wrong; so.could.this; }
catch.all.errors;
#REAL WORK
useful(i); fun(i); good(i);
} #end for
(au fait, il n'y a pas de documentation pour next
que je puisse trouver)
Quand je lance ceci, R
honks:
Error in value[[3L]](cond) : no loop for break/next, jumping to top level
Quel point de base me manque ici? Les tryCatch
sont clairement dans la boucle for
, alors pourquoi R
ne le sait-il pas?
La clé de l'utilisation de tryCatch
est de se rendre compte qu'elle renvoie un objet. S'il y avait une erreur à l'intérieur de tryCatch
alors cet objet héritera de la classe error
. Vous pouvez tester l'héritage de classe avec la fonction inherit
.
x <- tryCatch(stop("Error"), error = function(e) e)
class(x)
"simpleError" "error" "condition"
Modifier:
Quelle est la signification de l'argument error = function(e) e
? Cela m'a dérouté et je ne pense pas que cela soit bien expliqué dans la documentation. Ce qui se passe, c'est que cet argument intercepte tous les messages d'erreur provenant de l'expression que vous êtes tryCatch
ing. Si une erreur est détectée, elle est renvoyée comme la valeur de tryCatch
. Dans la documentation d'aide, cela est décrit comme un calling handler
. L'argument e
à l'intérieur de error=function(e)
est le message d'erreur provenant de votre code.
Je viens de l'ancienne école de programmation procédurale où l'utilisation de next
était une mauvaise chose. Je voudrais donc réécrire votre code quelque chose comme ça. (Notez que j'ai supprimé l'instruction next
à l'intérieur de tryCatch
.):
for (i in 1:39487) {
#ERROR HANDLING
possibleError <- tryCatch(
thing(),
error=function(e) e
)
if(!inherits(possibleError, "error")){
#REAL WORK
useful(i); fun(i); good(i);
}
} #end for
La fonction next
est documentée dans ?
Pour`.
Si vous voulez l'utiliser au lieu d'avoir votre routine de travail principale dans un if
, votre code devrait ressembler à ceci:
for (i in 1:39487) {
#ERROR HANDLING
possibleError <- tryCatch(
thing(),
error=function(e) e
)
if(inherits(possibleError, "error")) next
#REAL WORK
useful(i); fun(i); good(i);
} #end for
rm(list=ls())
for (i in -3:3) {
#ERROR HANDLING
possibleError <- tryCatch({
print(paste("Start Loop ", i ,sep=""))
if(i==0){
stop()
}
}
,
error=function(e) {
e
print(paste("Oops! --> Error in Loop ",i,sep = ""))
}
)
if(inherits(possibleError, "error")) next
print(paste(" End Loop ",i,sep = ""))
}
La seule explication vraiment détaillée que j'ai vue peut être trouvée ici: http://mazamascience.com/WorkingWithData/?p=912
Voici un extrait de code de ce billet de blog montrant comment fonctionne tryCatch
#!/usr/bin/env Rscript
# tryCatch.r -- experiments with tryCatch
# Get any arguments
arguments <- commandArgs(trailingOnly=TRUE)
a <- arguments[1]
# Define a division function that can issue warnings and errors
myDivide <- function(d, a) {
if (a == 'warning') {
return_value <- 'myDivide warning result'
warning("myDivide warning message")
} else if (a == 'error') {
return_value <- 'myDivide error result'
stop("myDivide error message")
} else {
return_value = d / as.numeric(a)
}
return(return_value)
}
# Evalute the desired series of expressions inside of tryCatch
result <- tryCatch({
b <- 2
c <- b^2
d <- c+2
if (a == 'suppress-warnings') {
e <- suppressWarnings(myDivide(d,a))
} else {
e <- myDivide(d,a) # 6/a
}
f <- e + 100
}, warning = function(war) {
# warning handler picks up where error was generated
print(paste("MY_WARNING: ",war))
b <- "changing 'b' inside the warning handler has no effect"
e <- myDivide(d,0.1) # =60
f <- e + 100
return(f)
}, error = function(err) {
# warning handler picks up where error was generated
print(paste("MY_ERROR: ",err))
b <- "changing 'b' inside the error handler has no effect"
e <- myDivide(d,0.01) # =600
f <- e + 100
return(f)
}, finally = {
print(paste("a =",a))
print(paste("b =",b))
print(paste("c =",c))
print(paste("d =",d))
# NOTE: Finally is evaluated in the context of of the inital
# NOTE: tryCatch block and 'e' will not exist if a warning
# NOTE: or error occurred.
#print(paste("e =",e))
}) # END tryCatch
print(paste("result =",result))
Une chose qui me manquait, qui sortir de la boucle for lors de l'exécution d'une fonction à l'intérieur d'une boucle for dans R rend clair, est la suivante:
next
ne fonctionne pas dans une fonction.Voldemort = TRUE
) de l'intérieur de votre fonction (dans mon cas tryCatch
) vers l'extérieur.Voldemort == TRUE
). Si c'est le cas, vous appelez break
ou next
en dehors de la fonction.J'ai trouvé d'autres réponses très déroutantes. Voici une implémentation extrêmement simple pour quiconque souhaite simplement passer à l'itération de boucle suivante en cas d'erreur
for (i in 1:10) {
skip_to_next <- FALSE
# Note that print(b) fails since b doesn't exist
tryCatch(print(b), error = function(e) { skip_to_next <<- TRUE})
if(skip_to_next) { next }
}