В каком порядке Python вычисляет выражения аргументов при обычном вызове функции?
Python вычисляет выражения аргументов слева направо, а затем связывает полученные значения с параметрами и начинает выполнять тело функции. Поэтому побочные эффекты в выражениях аргументов происходят до входа в функцию и в порядке их записи.
Фиксированный порядок вычисления делает поведение вызовов предсказуемым: разработчик может рассуждать о побочных эффектах без зависимости от оптимизаций интерпретатора. Это особенно важно для функций, которые читают или изменяют общее состояние.
Такой подход согласуется с общей моделью вычисления выражений Python: составные выражения вычисляются последовательно, а вызов функции начинается только после подготовки его аргументов.
Ошибка возникает, когда предполагают, что функция начинает выполняться сразу после появления первого аргумента или что аргументы могут вычисляться в произвольном порядке. Из-за этого можно неверно определить состояние объектов, порядок записей в журнале или результат вызова функций с побочными эффектами.
Важно отличать вычисление аргументов от связывания параметров. Сначала вычисляются все выражения аргументов, затем Python проверяет соответствие параметрам, и только после этого выполняется тело функции.
В обычном вызове Python последовательно вычисляет выражения аргументов слева направо. Это относится и к позиционным аргументам, и к выражениям, переданным как значения именованных аргументов. После вычисления создаётся набор фактических аргументов, который связывается с параметрами функции.
Перед выполнением тела receive список events содержит ['first', 'second', 'mode']. Если одно из выражений завершится исключением, тело функции не начнёт выполняться, а последующие выражения аргументов не будут вычислены.
Не следует смешивать это правило с вычислением значений параметров по умолчанию. Значения по умолчанию создаются при выполнении определения функции, а не при каждом вызове; порядок вычисления аргументов вызова к этому механизму не относится.
Практический компромисс очевиден: предсказуемый порядок полезен для контроля побочных эффектов, но сами побочные эффекты в аргументах ухудшают читаемость. Обычно лучше заранее вычислить сложные значения отдельными инструкциями или передавать чистые выражения.
В обработчике заказа один аргумент записывает событие аудита, а другой считывает текущий статус заказа. Если оба действия скрыты внутри вызова и порядок записи неочевиден, код становится хрупким: изменение порядка аргументов может изменить наблюдаемое состояние.
Рассматривались два варианта. Оставить вызов с побочными эффектами компактно — быстрее написать, но сложнее тестировать и сопровождать. Вынести действия в отдельные инструкции — немного многословнее, зато порядок операций явно виден и проще контролируется.
Выбран второй вариант: сначала получают статус и отдельно записывают аудит, затем передают готовые значения функции. Результат — отсутствие зависимости от скрытых эффектов аргументных выражений и более понятные тесты.
1. Что произойдёт, если первое выражение аргумента выбросит исключение?
Исключение немедленно прерывает вычисление вызова. Тело функции не выполняется, а выражения аргументов, расположенные правее, не вычисляются. Это позволяет использовать порядок вычисления для точного анализа того, какие побочные эффекты успели произойти до ошибки.
2. Выполняется ли тело функции после вычисления только части аргументов?
Нет. Python должен вычислить все аргументы, выполнить распаковку при её наличии и проверить возможность связать значения с параметрами. Тело начинается только после успешного завершения этой подготовки; ошибка в обязательном параметре или конфликт имен также возникает до выполнения тела.
3. Можно ли полагаться на порядок аргументов как на способ управления побочными эффектами?
На порядок вычисления полагаться можно, поскольку он определён семантикой Python. Однако использовать это как основной способ координации состояния не рекомендуется: зависимость между аргументами становится скрытой, а рефакторинг вызова может изменить поведение. Надёжнее сделать последовательность операций явной, если она важна для корректности.