web-dev-qa-db-fra.com

Utilisez try Catch skip to next value of loop on error?

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?

55
isomorphismes

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 tryCatching. 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
76
Andrie
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 = ""))

}
5
ewittry

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))
4
mmann1123

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.
  • Vous devez envoyer un signal ou un indicateur (par exemple, Voldemort = TRUE) de l'intérieur de votre fonction (dans mon cas tryCatch) vers l'extérieur.
  • (c'est comme modifier une variable publique globale à l'intérieur d'une fonction locale et privée)
  • Ensuite, en dehors de la fonction, vous vérifiez si le drapeau a été agité (est-ce que Voldemort == TRUE). Si c'est le cas, vous appelez break ou next en dehors de la fonction.
3
isomorphismes

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 }     
}
1
user5783745