102 Stimmen

Verwenden Sie tryCatch Sprung zum nächsten Wert der Schleife auf Fehler?

Ich habe ein paar andere SO-Fragen zu folgenden Themen gelesen tryCatch und Cuzzins, sowie die Dokumentation:

aber ich verstehe es trotzdem nicht.

Ich führe eine Schleife aus und möchte zu next wenn eine der wenigen Fehlerarten auftritt:

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

(Übrigens gibt es keine Dokumentation für next die ich finden kann)

Wenn ich das ausführe, R hupt:

Error in value[[3L]](cond) : no loop for break/next, jumping to top level

Welchen grundlegenden Punkt übersehe ich hier? Die tryCatch liegen eindeutig innerhalb der for Schleife, warum wird also nicht R Wussten Sie das?

105voto

stevec Punkte 25346

Andere Antworten fand ich sehr verwirrend. Hier ist eine extrem einfache Implementierung für alle, die im Falle eines Fehlers einfach zur nächsten Schleifeniteration übergehen wollen

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

104voto

Andrie Punkte 169813

Der Schlüssel zur Nutzung tryCatch ist die Erkenntnis, dass sie ein Objekt zurückgibt. Wenn es einen Fehler innerhalb der tryCatch dann erbt dieses Objekt von der Klasse error . Sie können die Klassenvererbung mit der Funktion inherit .

x <- tryCatch(stop("Error"), error = function(e) e)
class(x)
"simpleError" "error"       "condition"  

Edit :

Was ist die Bedeutung des Arguments error = function(e) e ? Das hat mich verwirrt, und ich glaube nicht, dass es in der Dokumentation gut erklärt ist. Was passiert, ist, dass dieses Argument alle Fehlermeldungen abfängt, die von dem Ausdruck stammen, den Sie gerade tryCatch ing. Wenn ein Fehler aufgetreten ist, wird er als Wert von tryCatch . In der Hilfedokumentation wird dies beschrieben als calling handler . Das Argument e innerhalb error=function(e) ist die Fehlermeldung, die in Ihrem Code entsteht.


Ich komme von der alten Schule der prozeduralen Programmierung, bei der die next war eine schlechte Sache. Ich würde Ihren Code also etwa so umschreiben. (Beachten Sie, dass ich das next Anweisung innerhalb der 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

Die Funktion next ist dokumentiert in ? für".

Wenn Sie das verwenden möchten, anstatt Ihre Hauptarbeitsroutine innerhalb einer if sollte Ihr Code etwa so aussehen:

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

7voto

ewittry Punkte 81
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 = ""))

}

5voto

isomorphismes Punkte 7955

Eine Sache, die ich vermisst habe, und zwar Ausbrechen aus der for-Schleife bei der Ausführung einer Funktion innerhalb einer for-Schleife in R deutlich macht, ist dies:

  • next funktioniert nicht innerhalb einer Funktion.
  • Sie müssen ein Signal oder eine Markierung senden (z. B., Voldemort = TRUE ) innerhalb Ihrer Funktion (in meinem Fall tryCatch ) nach außen.
  • (dies ist wie die Änderung einer globalen, öffentlichen Variablen innerhalb einer lokalen, privaten Funktion)
  • Außerhalb der Funktion prüfen Sie dann, ob die Flagge geschwenkt wurde (wird Voldemort == TRUE ). Wenn ja, rufen Sie break o next außerhalb der Funktion.

5voto

mmann1123 Punkte 4532

Die einzige wirklich ausführliche Erklärung, die ich gesehen habe, ist hier zu finden: http://mazamascience.com/WorkingWithData/?p=912

Hier ist ein Codeausschnitt aus diesem Blogbeitrag, der zeigt, wie tryCatch funktioniert

#!/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))

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X