Почему создание кортежа работает, если первый элемент является Исключением?

Мне сложно разобраться в этом, речь идет о ошибках, которые могут быть сделаны при создании исключения в Python 2.7:

try: raise [1, 2, 3, 4] except Exception as ex: print ex 

сообщение здесь «исключения должны быть классами старого стиля или производными от BaseException, а не списком». Эта часть одобрена, но когда я меняю ее на кортеж, я запутываюсь:

 try: raise (1, 2, 3, 4) except Exception as ex: print ex 

сообщение здесь «исключения должны быть классами старого стиля или производными от BaseException, а не int» – почему это интерпретируется как повышение int, а не кортежа?

Futhermore:

 try: raise (Exception, 'a message') except Exception as ex: print ex 

Здесь мы фактически поднимаем Exception (последовательное поведение по сравнению с предыдущим примером, где мы поднимаем int) – я кратко подумал, что это просто альтернативный способ для этого:

 try: raise Exception, 'a message' except Exception as ex: print ex 

Но в этом случае сообщение «сообщение» передается в Исключения ctor (как описано на docs.python.org)

Может кто-то объяснить 2-й и 3-й случаи, и, возможно, указать мне на код в интерпретаторе, который отвечает за это?

  • Python / Django: Как удалить лишние пробелы и вкладки из строки?
  • Схема Django Test с файловым сервером электронной почты
  • Не удается открыть websocket на мобильных устройствах
  • Python - случайным образом разбивает список на n почти равных частей
  • Сгенерируйте тепловую карту в MatPlotLib, используя набор данных рассеяния
  • 3D-преобразование Фурье
  • Python / BeautifulSoup - как удалить все теги из элемента?
  • Получение международных символов с веб-страницы?
  • 3 Solutions collect form web for “Почему создание кортежа работает, если первый элемент является Исключением?”

    Как указано в ссылке на python , оператор raise принимает до 3 выражений для создания создаваемого исключения:

    raise_stmt :: = "raise" [выражение ["," выражение ["," выражение]]]

    В python 2, если первое выражение является кортежем, python «разворачивает» кортеж рекурсивно, беря первый элемент, пока не найдет что-то другое, кроме кортежа. Это поведение удаляется с Python 3 (см. PEP 3109. Следующее правовое:

     >>> raise ((Exception, 'ignored'), 'ignored'), 'something', None Traceback (most recent call last): File "<stdin>", line 1, in <module> Exception: something 

    Документация объясняет остальное более подробно, но оператор raise ожидает, что первое значение будет классом Exception, второе значение рассматривается как значение исключения (сообщение), а третье значение – трассировка. Python заполняет None для последних двух значений, если отсутствует.

    Если первым значением является экземпляр вместо этого, второе значение должно быть None:

     >>> raise Exception('something'), 'something', None Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: instance exception may not have a separate value 

    Если вы используете кортеж из более чем 3 элементов, это приведет к возникновению синтаксической ошибки:

     >>> raise Exception, 'something', None, None File "<stdin>", line 1 raise Exception, 'something', None, None ^ SyntaxError: invalid syntax 

    Тем не менее, в вашем случае вы не подняли ни класс, ни экземпляр, так что сначала Python был некорректным; если я использую строку, она тоже будет жаловаться:

     >>> raise 'not an exception', 'something', None Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: exceptions must be old-style classes or derived from BaseException, not str 

    Конечно, правильный синтаксис:

     >>> raise Exception, 'something', None Traceback (most recent call last): File "<stdin>", line 1, in <module> Exception: something 

    http://docs.python.org/reference/simple_stmts.html#the-raise-statement

    "raise" [выражение ["," выражение ["," выражение]]]

    Если выражения не присутствуют, повышайте re-raises последнее исключение, которое было активным в текущей области … В противном случае raise оценивает выражения для получения трех объектов , используя None в качестве значения пропущенных выражений. Первые два объекта используются для определения типа и значения исключения.

    На самом деле, я думал, что python делает распаковку кортежей здесь

     try: raise (ValueError, "foo", ), "bar" except Exception as e: print e.message # foo or bar? 

    но если это так, результат будет «foo», а не «bar». Такое поведение, похоже, не документировано нигде, есть только короткая заметка о том, что он был сброшен в py3:

    В Python 2 следующая заявка на повышение является законной

    повышение ((E1, (E2, E3)), E4), V

    Интерпретатор берет первый элемент кортежа как тип исключения (рекурсивно), делая вышеописанное полностью эквивалентным

    поднять E1, V

    Начиная с Python 3.0, поддержка для добавления кортежей, подобных этому, будет удалена. Это изменение приведет к тому, что подгонки будут соответствовать методу throw () для объектов-генераторов, которые уже запрещают это.

    http://www.python.org/dev/peps/pep-3109/#id17

    По-видимому, Python также принимает непустой кортеж для первого выражения в выражении raise, несмотря на документацию (но, как указано в этом PEP ), и если это кортеж, он рекурсивно использует свой первый элемент для класса исключения. Позвольте мне показать вам код:

     >>> raise ValueError, 'sdf', None Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: sdf >>> raise (ValueError, 5), 'sdf', None Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: sdf 

    Несмотря на то, что я сказал в своем предыдущем комментарии, автоматическая распаковка отсутствует, потому что строка не передается классу исключений в следующем примере:

     >>> raise (ValueError, 'sdf', None) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError 

    Также, используя модуль python ast, мы видим, что в выражении повышения по умолчанию нет кортежа:

     >>> ast.dump(ast.parse('raise ValueError, "asd"')) "Module(body=[Raise(type=Name(id='ValueError', ctx=Load()), inst=Str(s='asd'), tback=None)])" 

    И если мы используем кортеж, это передается как аргумент типа:

     >>> ast.dump(ast.parse('raise (ValueError, "asd")')) "Module(body=[Raise(type=Tuple(elts=[Name(id='ValueError', ctx=Load()), Str(s='asd')], ctx=Load()), inst=None, tback=None)])" 
    Python - лучший язык программирования в мире.