На роботі я натрапив на 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, але idk, де його знайти, і, можливо, є простіший спосіб?