En el trabajo, me topé con una except
cláusula con un or
operador:
try:
# Do something.
except IndexError or KeyError:
# ErrorHandling
Sé que las clases de excepción deben pasarse como una tupla, pero me molestó que ni siquiera causara una SyntaxError
.
Así que primero quería investigar si realmente funciona. Y no lo hace.
>>> 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
Por lo tanto, no detectó la segunda excepción, y al mirar el código de bytes, se vuelve más claro por qué:
>>> 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
Para que podamos ver, la instrucción 14 primero carga la IndexError
clase en la pila. Luego verifica si ese valor es True
, lo cual es debido a la veracidad de Python y finalmente salta directamente a la instrucción 20 donde exception match
se realiza. Como la instrucción 18 se omitió, KeyError
nunca se cargó en la pila y, por lo tanto, no coincide.
Intenté con Python 2.7 y 3.6, el mismo resultado.
Pero entonces, ¿por qué es una sintaxis válida? Me imagino que es uno de los siguientes:
- Es un artefacto de una versión muy antigua de Python.
- En realidad, hay un caso de uso válido para usar
or
dentro de unaexcept
cláusula. - Es simplemente una limitación del analizador de Python que podría tener que aceptar cualquier expresión después de la
except
palabra clave.
Mi voto es sobre 3 (dado que vi un debate sobre un nuevo analizador para Python) pero espero que alguien pueda confirmar esa hipótesis. Porque si fuera 2 por ejemplo, ¡quiero saber ese caso de uso!
Además, no tengo ni idea de cómo continuaría esa exploración. Me imagino que tendría que profundizar en el código fuente del analizador CPython, pero no sé dónde encontrarlo y tal vez hay una manera más fácil.
fuente
except
declaración.except IndexError or KeyError
parece una cosa decente para escribir. Sin embargo, estoy de acuerdo con usted en que sería en contra de otros valores que Python trata de respetar.var == 1 or 2
, lo que para el ojo inexperto también "parece una cosa decente para escribir".Debería usar una n-tupla de tipos en lugar de una expresión lógica (que solo devuelve el primer elemento no falso):
fuente
or
Python todavía era válido.