it-swarm.com.de

Wie kann ich mit Ausnahmen in einem Listenverständnis in Python umgehen?

Ich habe ein Listenverständnis in Python, bei dem jede Iteration eine Ausnahme auslösen kann. 

Zum Beispiel , wenn ich:

eggs = (1,3,0,3,2)

[1/Egg for Egg in eggs]

Ich werde eine ZeroDivisionError-Ausnahme im 3. Element erhalten.

Wie kann ich mit dieser Ausnahme umgehen und das Listenverständnis weiterhin ausführen?

Die einzige Möglichkeit, die mir einfällt, ist die Verwendung einer Hilfsfunktion:

def spam(Egg):
    try:
        return 1/Egg
    except ZeroDivisionError:
        # handle division by zero error
        # leave empty for now
        pass

Aber das sieht für mich etwas umständlich aus.

Gibt es einen besseren Weg, dies in Python zu tun?

Hinweis: Dies ist ein einfaches Beispiel (siehe "für Beispiel" oben), das ich entwickelt habe, da mein reales Beispiel einen Kontext erfordert. Ich bin nicht daran interessiert, Fehler durch Nullen zu vermeiden, sondern Ausnahmen in einem Listenverständnis zu behandeln.

78
Nathan Fellman

Es gibt keinen integrierten Ausdruck in Python, mit dem Sie eine Ausnahme ignorieren können (oder alternative Werte & c im Falle von Ausnahmen zurückgeben). Daher ist es buchstäblich unmöglich, "Ausnahmen in einem Listenverständnis zu behandeln", da ein Listenverständnis ein Ausdruck ist enthält andere Ausdrücke, nichts weiter (dh keine Anweisungen und nur Anweisungen können Ausnahmen fangen/ignorieren/behandeln).

Funktionsaufrufe sind Ausdruck, und die Funktionskörper können alle Anweisungen enthalten, die Sie möchten. Daher ist das Delegieren der Auswertung des ausnahmebedingten Unterausdrucks an eine Funktion, wie Sie bemerkt haben, eine praktikable Problemumgehung (andere, wenn möglich, sind möglich) Überprüfung von Werten, die Ausnahmen auslösen könnten (wie auch in anderen Antworten vorgeschlagen).

Die richtigen Antworten auf die Frage, wie mit Ausnahmen bei einem Listenverständnis umzugehen ist, drücken alle einen Teil dieser ganzen Wahrheit aus: 1) wörtlich, d. H. Lexikalisch im Verständnis selbst, das geht nicht; 2) Sie delegieren den Job praktisch an eine Funktion oder suchen nach fehleranfälligen Werten, wenn dies machbar ist. Ihre wiederholte Behauptung, dies sei keine Antwort, ist daher nicht begründet.

70
Alex Martelli

Mir ist klar, dass diese Frage ziemlich alt ist, aber Sie können auch eine allgemeine Funktion erstellen, um solche Dinge zu erleichtern:

def catch(func, handle=lambda e : e, *args, **kwargs):
    try:
        return func(*args, **kwargs)
    except Exception as e:
        return handle(e)

Dann in deinem Verständnis:

eggs = (1,3,0,3,2)
[catch(lambda : 1/Egg) for Egg in eggs]
[1, 0, ('integer division or modulo by zero'), 0, 0]

Sie können natürlich die Standard-Handle-Funktion so einrichten, wie Sie möchten (sagen Sie lieber "None" als Standard).

Ich hoffe, das hilft Ihnen oder zukünftigen Zuschauern dieser Frage!

Hinweis: In Python 3 würde ich nur das Argumentschlüsselwort 'handle' verwenden und es an das Ende der Argumentliste setzen. Dies würde tatsächlich vorübergehende Argumente und solche durch den Fang viel natürlicher machen.

78
Bryan Head

Sie können verwenden

[1/Egg for Egg in eggs if Egg != 0]

dies überspringt einfach Elemente, die Null sind.

19
Peter

Nein, es gibt keinen besseren Weg. In vielen Fällen können Sie die Vermeidung wie bei Peter verwenden

Ihre andere Option besteht darin, keine Verständnisse zu verwenden

eggs = (1,3,0,3,2)

result=[]
for Egg in eggs:
    try:
        result.append(Egg/0)
    except ZeroDivisionError:
        # handle division by zero error
        # leave empty for now
        pass

Es liegt an Ihnen zu entscheiden, ob dies umständlicher ist oder nicht

7
John La Rooy

Ich denke, eine Helferfunktion, wie sie von demjenigen vorgeschlagen wird, der die ursprüngliche Frage stellt, und auch Bryan Head, ist gut und überhaupt nicht schwerfällig. Eine einzige Zeile mit magischem Code, der die ganze Arbeit erledigt, ist nicht immer möglich. Daher ist eine Hilfsfunktion die perfekte Lösung, wenn for-Schleifen vermieden werden sollen. Ich würde es jedoch zu diesem ändern:

# A modified version of the helper function by the Question starter 
def spam(Egg):
    try:
        return 1/Egg, None
    except ZeroDivisionError as err:
        # handle division by zero error        
        return None, err

Die Ausgabe wird diese [(1/1, None), (1/3, None), (None, ZeroDivisionError), (1/3, None), (1/2, None)] sein. Mit dieser Antwort haben Sie die volle Kontrolle, um auf beliebige Weise fortzufahren. 

3
Elmex80s