Au travail, je suis tombé sur une except
clause avec un or
opérateur:
try:
# Do something.
except IndexError or KeyError:
# ErrorHandling
Je sais que les classes d'exception doivent être passés comme un tuple, mais il me Bugged qu'il ne serait même pas causer SyntaxError
.
J'ai donc d'abord voulu vérifier si cela fonctionnait réellement. Et ce n'est pas le cas.
>>> 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
Donc, il n'a pas intercepté la deuxième exception, et en regardant le bytecode, il devient plus clair pourquoi:
>>> 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
On voit donc que l'instruction 14 charge d'abord la IndexError
classe sur la pile. Ensuite, il vérifie si cette valeur est True
, ce qui est dû à la véracité de Python et saute finalement directement à l'instruction 20 où exception match
cela est fait. Étant donné que l'instruction 18 a été ignorée, KeyError
n'a jamais été chargée dans la pile et ne correspond donc pas.
J'ai essayé avec Python 2.7 et 3.6, même résultat.
Mais alors, pourquoi est-ce une syntaxe valide? J'imagine que c'est l'un des suivants:
- C'est un artefact d'une version très ancienne de Python.
- Il existe en fait un cas d'utilisation valide à utiliser
or
dans uneexcept
clause. - C'est simplement une limitation de l'analyseur Python qui pourrait devoir accepter n'importe quelle expression après le
except
mot - clé.
Mon vote est sur 3 (étant donné que j'ai vu une discussion sur un nouvel analyseur pour Python) mais j'espère que quelqu'un pourra confirmer cette hypothèse. Parce que si c'était 2 par exemple, je veux connaître ce cas d'utilisation!
De plus, je ne sais pas du tout comment je continuerais cette exploration. J'imagine que je devrais creuser dans le code source de l'analyseur CPython mais idk où le trouver et peut-être qu'il existe un moyen plus simple?
la source
except
instruction.except IndexError or KeyError
ressemble à une chose décente à écrire. Cependant, je suis d'accord avec vous que ce serait contre d'autres valeurs que Python essaie de respecter.var == 1 or 2
, ce qui à l'œil non averti "ressemble également à une chose décente à écrire".Vous devez utiliser un n-tuple de types au lieu d'une expression logique (qui renvoie simplement le premier élément non faux):
la source
or
Python était toujours valide.