Ответ 1
Почему для обработки нескольких исключений требуется кортеж, а не список?
Обработка ошибок, написанная на C, использует проверку типов для особого случая кортежа перед другой проверкой типов и обработкой исключений, так что могут быть обнаружены многочисленные типы исключений.
По крайней мере один разработчик ядра Python рекомендует использовать обработку исключений для потока управления. Добавление списков в качестве дополнительного типа для проверки будет работать против этой стратегии.
Похоже, что расширение этого, чтобы включить наборы или списки, не было специально решено основной командой разработчиков, хотя я с удовольствием упомяну об этом, если это можно будет найти. В списке рассылки было много спекуляций (другой ответ здесь приводит один ответ).
После выполнения анализа ниже, и в контексте обсуждения списка рассылки, я думаю, что аргументация очевидна. Я не предлагаю предлагать добавлять другие контейнеры.
Демонстрация со списком неудач по сравнению с кортежами
exceptions = TypeError, RuntimeError
list_of_exceptions = list(exceptions)
Поймать кортеж исключений работает:
try:
raise TypeError('foo')
except exceptions as error:
print(error)
выходы:
foo
Но перехват списка исключений не работает:
try:
raise TypeError('foo')
except list_of_exceptions as error:
print(error)
принтами:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: foo
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: catching classes that do not inherit from BaseException is not allowed
Это демонстрирует, что мы делаем проверку типов для особого случая кортежа. Это, конечно, сделает код медленнее, добавив еще один тип для проверки, и разработчики ядра говорили, что было бы неплохо использовать обработку исключений для потока управления в Python какое-то время.
Анализ исходного кода
Анализ источника согласуется с этим выводом.
Грамматика
Это не проблема для Python грамматики или анализа. Он примет любое выражение. Таким образом, любое выражение, которое приводит к исключению или кортежу исключений, должно быть законным.
Демонтажные
Если мы разберем функцию, которая делает это в Python 3, мы увидим, что она ищет соответствие исключению с операцией сравнения.
def catch(exceptions):
try:
raise Exception
except exceptions:
pass
import dis
dis.dis(catch)
Какие выводы:
2 0 SETUP_EXCEPT 10 (to 13)
3 3 LOAD_GLOBAL 0 (Exception)
6 RAISE_VARARGS 1
9 POP_BLOCK
10 JUMP_FORWARD 18 (to 31)
4 >> 13 DUP_TOP
14 LOAD_FAST 0 (exceptions)
17 COMPARE_OP 10 (exception match)
...
Это приводит нас внутрь интерпретатора Python.
Поток внутреннего контроля - детали реализации CPython
Сначала поток управления CPython проверяет, является ли значение кортежем. Если это так, он перебирает кортеж с использованием кода, специфичного для кортежа, и ищет значение, являющееся исключением:
case PyCmp_EXC_MATCH:
if (PyTuple_Check(w)) {
Py_ssize_t i, length;
length = PyTuple_Size(w);
for (i = 0; i < length; i += 1) {
PyObject *exc = PyTuple_GET_ITEM(w, i);
if (!PyExceptionClass_Check(exc)) {
_PyErr_SetString(tstate, PyExc_TypeError,
CANNOT_CATCH_MSG);
return NULL;
}
}
}
else {
if (!PyExceptionClass_Check(w)) {
_PyErr_SetString(tstate, PyExc_TypeError,
CANNOT_CATCH_MSG);
return NULL;
}
}
res = PyErr_GivenExceptionMatches(v, w);
break;
Добавление другого типа потребовало бы большего внутреннего потока управления, замедляя поток управления внутри интерпретатора Python.
Размеры контейнеров Python
Кортежи - это легкие массивы указателей. Так же как и списки, но им может быть выделено дополнительное пространство, чтобы вы могли быстро добавить к ним (вплоть до того момента, когда они должны увеличиться). В Python 3.7.3 для Linux:
>>> from sys import getsizeof
>>> getsizeof((1,2,3))
72
>>> getsizeof([1,2,3])
88
Наборы занимают еще больше места, потому что они являются хеш-таблицами. У них есть хеш объекта, который они содержат, а также указатель на то, на что они указывают.
Заключение
Это для основной команды разработчиков CPython, чтобы обсудить и принять решение.
Но мой вывод заключается в том, что замедление потока управления в Python путем проверки других типов даже на уровне C будет работать против стратегии использования обработки исключений для потока управления в модулях Python.
После рассуждений вышеизложенного я бы не предложил, чтобы они добавили это.