2016-07-20 15 views
2

Betrachten Sie den folgenden Code ein:variabler Bereich in R tryCatch Block: ist << - notwendig, um lokale Variable zu ändern, die vor tryCatch definiert wurde?

test1 <- "a" 
test2 <- "a" 
tryCatch(stop(), error= function(err){ 
    print(test1) 
    print(test2) 
    test1 <- "b" 
    test2 <<- "b" 
}) 

Ergebnis:

print(test1) 
[1] "a" 
print(test2) 
[1] "b" 

Der Wert der Variablen test1 ist sichtbar im TryCatch Block, aber es mit wechselnden "< -" Betreiber hat keinen Einfluss auf ihren Wert außerhalb der tryCatch-Block.

Wenn ein neuer Wert mit < < zugewiesen wird - hat dies den gewünschten Effekt. Warum?

Verwendet den < - Operator innerhalb des tryCatch-Blocks eine empfohlene Möglichkeit, den Wert einer lokalen Variablen außerhalb dieses Blocks zu ändern? Könnte es zu unerwarteten Nebeneffekten kommen?

EDIT: Beruht der folgende Code auf einer Bernhard-Antwort für den richtigen Ansatz für dieses Problem?

test1 <- "a" 
test2 <- "a" 
new_values<-tryCatch(
    { 
    print("hello") 
    stop() 
    } 
, error= function(err){ 
    # I want to change the test1 and test 2 variables to "b" only if error occurred. 
    test1 <- "b" 
    test2 <- "b" 
    return(list(test1=test1,test2=test2)) 
}) 
if (is.list(new_values)) 
{ 
    test1<-new_values$test1 
    test2<-new_values$test2 
} 

Ergebnis:

> print(test1) 
[1] "b" 
> print(test2) 
[1] "b" 
+0

Es ist technisch in einer anonymen Funktion aufgerufen, wenn der Fehler auftritt. Alle traditionellen [Scoping-Regeln] (http://adv-r.had.co.nz/Functions.html#lexical-scoping) gelten. Während "<< -" stark davor gewarnt wird, ist es ein Hilfsmittel von R, um vernünftig verwendet zu werden. Es wird häufig beim Schreiben von Paketen benötigt und sollte in normalen Analysen/Skripten entweder stark kommentiert oder vermieden werden. – hrbrmstr

Antwort

1

Die ‚< < -‘ für Nebenwirkungen gemacht, die R. Nutzung gehören nicht es nie, oder nur, wenn der Speicher oder Geschwindigkeit Kraft Sie, dies zu tun. Ein Block hat seinen eigenen Anwendungsbereich und wenn Sie aus einem Block zum ‚außen‘ environement geben Daten wollen, dass return() für diese Aufgabe ist:

test2 <- "a" 

test2 <- tryCatch(stop(), error= function(err){ 
    somevariable <- "b" 
    return(somevariable) 
}) 

Dies macht es jedem klar, dass die Toplevel test2 wird auf "a" gesetzt, und dann wird dieser Toplevel test2 auf etwas anderes gesetzt. Mit '< < -' passiert es leicht, dass einige Funktionen Toplevel test2 ändern und jemand fragt sich, warum Toplevel test2 überhaupt geändert wurde. Nur nicht < < -.

Wenn mehr als ein Ergebnis zurückgegeben werden muss, eine Liste oder ein Objekt der Ergebnisse zurückgeben.

EDIT: Das OP hat darauf hingewiesen, dass Sie mit den Return-Anweisungen vorsichtig sein müssen, da sie nicht nur den aktuellen Block, sondern auch die aktuelle Funktion beenden. Eine mögliche Lösung besteht darin, die Berechnungen in Funktionen statt in einfachen Blöcken auszuführen. Das folgende Beispiel soll dies veranschaulichen:

safediv <- function(a, b){ 
    normalDo <- function(a, b){ 
     return(list(value=a/b, message=NULL)) 
    } 
    exceptionalDo <- function(err){ 
     return(list(value=NaN, message="caught an error! Change global variable?")) 
    } 
    results <- tryCatch(normalDo(a, b), error=exceptionalDo) 
    print("safediv is still running after the returns within the functions.") 
    return(results) 
} 

# try it out 
safediv(5, 3) 
safediv(5, 0) 
safediv(5, "a") 
+0

Eines ist mir bei dieser Lösung nicht klar. Wenn beispielsweise eine print() -Ausgabe im Hauptteil des tryCatch-Blocks ausgegeben wird und kein Fehler auftritt, wird sie in die Variable test2 zurückgegeben. Wenn ein Fehler auftritt, wird der Wert der Variable test2 durch die Fehlerfunktion festgelegt. Das "Äußere" muss also irgendwie die Variable test2 analysieren, um zu unterscheiden, ob kein Fehler aufgetreten ist, und es enthält eine Kopie der Druckausgabe, die verworfen werden kann, oder es ist ein Fehler aufgetreten, und diese Änderung muss an die Variablen "außerhalb" weitergegeben werden . – tomas

+0

Ich habe meine Frage mit einer versuchten Komplettlösung basierend auf Ihrem Rat und meinem früheren Kommentar bearbeitet. Ist es Ihrer Meinung nach richtig? – tomas

+0

Das sieht gut aus. Ich würde wahrscheinlich das 'if (is.list (..)) 'part und gebe stattdessen eine Liste mit entsprechenden Werten in beiden Fällen/Blöcken zurück, aber dies kann nur ich sein. – Bernhard