Bei der Arbeit, stieß ich auf eine except
Klausel mit einem or
Betreiber:
try:
# Do something.
except IndexError or KeyError:
# ErrorHandling
Ich weiß, dass die Ausnahmeklassen als Tupel übergeben werden sollten, aber es hat mich gestört, dass es nicht einmal eine verursachen würde SyntaxError
.
Also wollte ich zuerst untersuchen, ob es tatsächlich funktioniert. Und das tut es nicht.
>>> def with_or_raise(exc):
... try:
... raise exc()
... except IndexError or KeyError:
... print('Got ya!')
...
>>> with_or_raise(IndexError)
Got ya!
>>> with_or_raise(KeyError)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in with_or_raise
KeyError
Die zweite Ausnahme wurde also nicht abgefangen, und wenn man sich den Bytecode ansieht, wird klarer, warum:
>>> import dis
>>> dis.dis(with_or_raise)
2 0 SETUP_EXCEPT 10 (to 12)
3 2 LOAD_FAST 0 (exc)
4 CALL_FUNCTION 0
6 RAISE_VARARGS 1
8 POP_BLOCK
10 JUMP_FORWARD 32 (to 44)
4 >> 12 DUP_TOP
14 LOAD_GLOBAL 0 (IndexError)
16 JUMP_IF_TRUE_OR_POP 20
18 LOAD_GLOBAL 1 (KeyError)
>> 20 COMPARE_OP 10 (exception match)
22 POP_JUMP_IF_FALSE 42
24 POP_TOP
26 POP_TOP
28 POP_TOP
5 30 LOAD_GLOBAL 2 (print)
32 LOAD_CONST 1 ('Got ya!')
34 CALL_FUNCTION 1
36 POP_TOP
38 POP_EXCEPT
40 JUMP_FORWARD 2 (to 44)
>> 42 END_FINALLY
>> 44 LOAD_CONST 0 (None)
46 RETURN_VALUE
Wie wir sehen können, lädt Befehl 14 zuerst die IndexError
Klasse auf den Stapel. Dann prüft es, ob dieser Wert ist True
, was auf die Python-Wahrhaftigkeit zurückzuführen ist, und springt schließlich direkt zu Anweisung 20, wo exception match
dies getan wird. Da Befehl 18 übersprungen wurde, KeyError
wurde er nie auf den Stapel geladen und stimmt daher nicht überein.
Ich habe mit Python 2.7 und 3.6 das gleiche Ergebnis versucht.
Aber warum ist die Syntax dann gültig? Ich stelle mir vor, dass es eines der folgenden ist:
- Es ist ein Artefakt aus einer wirklich alten Version von Python.
- Es gibt tatsächlich einen gültigen Anwendungsfall für die Verwendung
or
innerhalb einerexcept
Klausel. - Dies ist lediglich eine Einschränkung des Python-Parsers, der möglicherweise einen Ausdruck nach dem
except
Schlüsselwort akzeptieren muss .
Meine Stimme ist bei 3 (da ich einige Diskussionen über einen neuen Parser für Python gesehen habe), aber ich hoffe, dass jemand diese Hypothese bestätigen kann. Denn wenn es zum Beispiel 2 wäre, würde ich diesen Anwendungsfall wissen wollen!
Außerdem habe ich keine Ahnung, wie ich diese Erkundung fortsetzen würde. Ich stelle mir vor, ich müsste mich in den Quellcode des CPython-Parsers vertiefen, aber ich weiß nicht, wo ich ihn finden kann, und vielleicht gibt es einen einfacheren Weg?
quelle
except
Anweisung zu verwenden.except IndexError or KeyError
scheint schließlich eine anständige Sache zu sein. Ich stimme Ihnen jedoch zu, dass es gegen einige andere Werte verstößt, die Python zu respektieren versucht.var == 1 or 2
, was für das ungeübte Auge auch "wie eine anständige Sache zum Schreiben aussieht".Sie sollten ein n-Tupel von Typen anstelle eines logischen Ausdrucks verwenden (der nur das erste nicht falsche Element zurückgibt):
quelle
or
Python noch gültig ist.