Utilisez tryCatch passer à la valeur suivante de boucle en cas d'erreur?
j'ai lu quelques autres questions sur tryCatch
et cuzzins, ainsi que la documentation:
- la gestion des exceptions dans R
- attraper une erreur et puis la logique
- Comment puis-je vérifier si un appel de fonction entraîne un avertissement?
- Problèmes avec les Parcelles en Boucle
mais je ne comprends toujours pas.
j'exécute une boucle et je veux passer à next
si l'un des quelques types d'erreurs se produisent:
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
(soit dit en passant, il n'y a pas de documentation pour next
que je peux trouver)
quand j'exécute ceci, R
honks:
Error in value[[3L]](cond) : no loop for break/next, jumping to top level
Qu'est-ce qui me manque ici? Le tryCatch
est clairement dans la boucle for
, alors pourquoi R
ne le sait pas?
4 réponses
la clé pour utiliser tryCatch
est de réaliser qu'il retourne un objet. S'il y avait une erreur à l'intérieur du 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"
Edit:
que signifie l'argument error = function(e) e
? Cela m'a déconcerté, et je ne pense pas que ce soit bien expliqué dans la documentation. Ce qui se passe est que cet argument saisit tous les messages d'erreur qui proviennent de l'expression que vous êtes tryCatch
ing. Si une erreur est détectée, elle est renvoyée avec la valeur tryCatch
. Dans la documentation d'aide, ceci 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 la programmation procédurale où l'utilisation next
était une mauvaise chose. Donc je réécrirais ton code quelque chose comme ça. (Notez que j'ai supprimé la mention next
à l'intérieur de la mention 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 à l'intérieur de ?
pour".
si vous voulez utiliser cela au lieu d'avoir votre routine de travail principale à l'intérieur d'un if
, votre code devrait ressembler à quelque chose comme 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
la seule explication vraiment détaillée que j'ai vu se trouve 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))
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 = ""))
}
une chose que je manquais, qui rupture de boucle for lors de l'exécution d'une fonction à l'intérieur d'une boucle for Dans R fait clair, est ceci:
-
next
ne fonctionne pas à l'intérieur d'une fonction. - vous devez envoyer un signal ou un drapeau (par exemple,
Voldemort = TRUE
) de l'intérieur de votre fonction (dans mon castryCatch
) à l'extérieur. - (c'est comme modifier une variable publique globale à l'intérieur d'un privé, local de la fonction)
- puis en dehors de la fonction, vous vérifiez si le drapeau a été agité (fait
Voldemort == TRUE
). Si c'est le cas, vous appelezbreak
ounext
en dehors de la fonction.