На работе я наткнулся на предложение except
с оператором or
:
try:
# Do something.
except IndexError or KeyError:
# ErrorHandling
Я знаю, что классы исключений должны быть переданы в виде кортежа, но мне это не понравилосьЭто даже вызывает SyntaxError
.
Итак, сначала я хотел выяснить, действительно ли это работает. И это не так.
>>> 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
Таким образом, он не уловил второе исключение, и, глядя на байт-код, становится понятнее, почему:
>>> 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
Итак, мы видим, инструкция14 сначала загружает класс IndexError
в стек. Затем он проверяет, является ли это значение True
, что связано с правдивостью Python, и, наконец, сразу переходит к инструкции 20, где выполняется exception match
. Поскольку инструкция 18 была пропущена, KeyError
никогда не загружался в стек и поэтому не совпадает.
Я пробовал с Python 2.7 и 3.6, тот же результат.
Но тогда, почемуэто правильный синтаксис? Я представляю, что это одно из следующего:
- Это артефакт из действительно старой версии Python.
- На самом деле есть действительный вариант использования
or
внутри except
предложение. - Это просто ограничение синтаксического анализатора Python, который может принимать любое выражение после ключевого слова
except
.
Мой голос равен 3 (если я виделнекоторое обсуждение нового парсера для Python), но я надеюсь, что кто-то может подтвердить эту гипотезу. Потому что, если бы это было 2, например, я хочу знать этот вариант использования!
Кроме того, я немного не понимаю, как бы я продолжил это исследование. Я полагаю, мне нужно было бы покопаться в исходном коде парсера CPython, но не знаю, где его найти, и, может быть, есть более простой способ?