Al lavoro, mi sono imbattuto in una except
clausola con un or
operatore:
try:
# Do something.
except IndexError or KeyError:
# ErrorHandling
So che le classi di eccezione dovrebbero essere passate come una tupla, ma mi ha infastidito il fatto che non causerebbe nemmeno a SyntaxError
.
Quindi, prima ho voluto indagare se funziona davvero. E non lo fa.
>>> 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
Quindi non ha colto la seconda eccezione e, guardando il bytecode, diventa più chiaro il perché:
>>> 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
Quindi, possiamo vedere, l'istruzione 14 prima carica la IndexError
classe nello stack. Quindi controlla se quel valore è True
, cosa che è a causa della verità di Python e infine passa direttamente all'istruzione 20 dove exception match
viene fatto. Poiché l'istruzione 18 è stata ignorata, KeyError
non è mai stata caricata nello stack e quindi non corrisponde.
Ho provato con Python 2.7 e 3.6, stesso risultato.
Ma allora, perché è una sintassi valida? Immagino che sia uno dei seguenti:
- È un artefatto di una versione davvero vecchia di Python.
- In realtà esiste un caso d'uso valido per l'utilizzo
or
all'interno di unaexcept
clausola. - È semplicemente una limitazione del parser Python che potrebbe dover accettare qualsiasi espressione dopo la
except
parola chiave.
Il mio voto è sul 3 (dato che ho visto alcune discussioni su un nuovo parser per Python) ma spero che qualcuno possa confermare quell'ipotesi. Perché se fosse 2 per esempio, voglio sapere quel caso d'uso!
Inoltre, sono un po 'all'oscuro di come continuare questa esplorazione. Immagino che dovrei scavare nel codice sorgente del parser CPython ma idk dove trovarlo e forse c'è un modo più semplice?