Spec-Zone.ru › Python 3.12

Выражения

В этой главе объясняется значение элементов выражений в Python.

Примечания к синтаксису: В этой и следующих главах для описания синтаксиса, а не лексического анализа, будет использоваться расширенная нотация БНФ. Если (одна из альтернатив) синтаксического правила имеет вид

name ::= othername

и семантика не указана, семантика этой формы name совпадает с семантикой othername.

6.1. Арифметические преобразования

Когда в приведенном ниже описании арифметического оператора используется фраза «числовые аргументы преобразуются к общему типу», это означает, что реализация оператора для встроенных типов работает следующим образом:

  • Если хотя бы один аргумент является комплексным числом, другой преобразуется к комплексному типу;
  • в противном случае, если хотя бы один аргумент является числом с плавающей точкой, другой преобразуется к типу с плавающей точкой;
  • в противном случае оба аргумента должны быть целыми числами, и преобразование не требуется.

Для некоторых операторов действуют дополнительные правила (например, для строки в качестве левого аргумента оператора ‘%’). Расширения должны определять собственное поведение преобразования.

6.2. Атомы

Атомы — это наиболее базовые элементы выражений. Самые простые атомы — это идентификаторы или литералы. Формы, заключенные в круглые, квадратные или фигурные скобки, также синтаксически классифицируются как атомы. Синтаксис атомов:

atom      ::= identifier | literal | enclosure
enclosure ::= parenth_form | list_display | dict_display | set_display
              | generator_expression | yield_atom

6.2.1. Идентификаторы (имена)

Идентификатор, используемый в качестве атома, является именем. Лексическое определение приведено в разделе Идентификаторы и ключевые слова, а описание именования и связывания — в разделе Именование и связывание.

Если имя связано с объектом, вычисление атома возвращает этот объект. Если имя не связано ни с каким объектом, попытка его вычислить вызывает исключение NameError.

6.2.1.1. Преобразование приватных имен

Если идентификатор, текстуально встречающийся в определении класса, начинается с двух или более символов подчеркивания и не заканчивается двумя или более символами подчеркивания, он считается приватным именем этого класса.

См. также

Определения классов.

Точнее, перед генерацией кода приватные имена преобразуются в более длинную форму. Если преобразованное имя длиннее 255 символов, может быть выполнено усечение, определяемое реализацией.

Преобразование не зависит от синтаксического контекста, в котором используется идентификатор, но преобразованию подвергаются только следующие приватные идентификаторы:

  • Любое имя, используемое как имя переменной, которой присваивается значение или к которой обращаются, а также любое имя атрибута, к которому обращаются.

    Однако атрибут __name__ вложенных функций, классов и псевдонимов типов не подвергается преобразованию.

  • Имя импортируемого модуля, например __spam в import __spam. Если модуль является частью пакета (то есть его имя содержит точку), имя не подвергается преобразованию; например, __foo в import __foo.bar не преобразуется.
  • Имя импортируемого элемента, например __f в from spam import __f.

Правило преобразования определено следующим образом:

  • Имя класса, из которого удалены начальные символы подчеркивания и перед которым добавлен один начальный символ подчеркивания, ставится перед идентификатором. Например, идентификатор __spam, встречающийся в классе с именем Foo, _Foo или __Foo, преобразуется в _Foo__spam.
  • Если имя класса состоит только из символов подчеркивания, преобразование не выполняется. Например, идентификатор __spam, встречающийся в классе с именем _ или __, остается без изменений.

6.2.2. Литералы

Python поддерживает строковые и байтовые литералы, а также различные числовые литералы:

literal ::= stringliteral | bytesliteral
            | integer | floatnumber | imagnumber

Вычисление литерала возвращает объект указанного типа (строка, байты, целое число, число с плавающей точкой, комплексное число) с указанным значением. В случае литералов с плавающей точкой и мнимых (комплексных) литералов значение может быть приближенным. Подробности см. в разделе Литералы.

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

6.2.3. Формы в скобках

Форма в скобках — это необязательный список выражений, заключенный в круглые скобки:

parenth_form ::= "(" [starred_expression] ")"

Выражение в скобках возвращает результат вычисления этого списка выражений: если список содержит хотя бы одну запятую, он возвращает кортеж; в противном случае он возвращает единственное выражение, составляющее список.

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

Обратите внимание, что кортежи создаются не с помощью скобок, а с помощью запятой. Исключение — пустой кортеж, для которого скобки необходимы: разрешение использовать в выражениях незаключенное в скобки «ничто» приводило бы к неоднозначности и позволяло бы оставаться незамеченными распространенным опечаткам.

6.2.4. Отображения списков, множеств и словарей

Для создания списка, множества или словаря в Python предусмотрен специальный синтаксис, называемый «отображениями». Для каждого из них есть два варианта:

  • либо содержимое контейнера перечисляется явно,
  • либо оно вычисляется с помощью набора инструкций цикла и фильтрации, называемого генератором контейнера.

Общие синтаксические элементы генераторов контейнеров:

comprehension ::= assignment_expression comp_for
comp_for      ::= ["async"] "for" target_list "in" or_test [comp_iter]
comp_iter     ::= comp_for | comp_if
comp_if       ::= "if" or_test [comp_iter]

Генератор контейнера состоит из одного выражения, за которым следует как минимум одна часть for и ноль или более частей for или if. В этом случае элементы нового контейнера — это элементы, которые были бы получены, если рассматривать каждую из частей for или if как блок, вкладывая их слева направо, и вычислять выражение для получения элемента при каждом достижении самого внутреннего блока.

Однако, за исключением итерируемого выражения в самой левой части for, генератор контейнера выполняется в отдельной неявно вложенной области видимости. Это гарантирует, что имена, которым присваиваются значения в целевом списке, не «утекают» во внешнюю область видимости.

Итерируемое выражение в самой левой части for вычисляется непосредственно во внешней области видимости, а затем передается в качестве аргумента неявно вложенной области видимости. Последующие части for и любые условия фильтрации в самой левой части for нельзя вычислить во внешней области видимости, поскольку они могут зависеть от значений, полученных из самой левой итерируемой последовательности. Например: [x*y for x in range(10) for y in range(x, x+10)].

Чтобы гарантировать, что результатом генератора контейнера всегда будет контейнер соответствующего типа, во вложенной области видимости запрещены выражения yield и yield from.

Начиная с Python 3.6, в функции async def часть async for может использоваться для итерации по асинхронному итератору. Генератор контейнера в функции async def может содержать часть for или async for после начального выражения, дополнительные части for или async for, а также выражения await.

Если генератор контейнера содержит части async for или выражения await либо другие асинхронные генераторы контейнеров где-либо, кроме итерируемого выражения в самой левой части for, он называется асинхронным генератором контейнера. Асинхронный генератор контейнера может приостанавливать выполнение корутинной функции, в которой он находится. См. также PEP 530.

Добавлено в версии 3.6: Добавлена поддержка асинхронных генераторов контейнеров.

Изменено в версии 3.8: yield и yield from запрещены во вложенной области видимости.

Изменено в версии 3.11: Теперь асинхронные генераторы контейнеров разрешены внутри генераторов контейнеров в асинхронных функциях. Внешние генераторы контейнеров неявно становятся асинхронными.

6.2.5. Отображения списков

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

list_display ::= "[" [flexible_expression_list | comprehension] "]"

Отображение списка возвращает новый объект-список, содержимое которого задается либо списком выражений, либо генератором контейнера. Если задан список выражений, разделенных запятыми, его элементы вычисляются слева направо и в том же порядке помещаются в объект-список. Если задан генератор контейнера, список создается из элементов, полученных в результате его выполнения.

6.2.6. Отображения множеств

Отображение множества записывается в фигурных скобках и отличается от отображения словаря отсутствием двоеточий, разделяющих ключи и значения:

set_display ::= "{" (flexible_expression_list | comprehension) "}"

Отображение множества возвращает новый изменяемый объект-множество, содержимое которого задается либо последовательностью выражений, либо генератором контейнера. Если задан список выражений, разделенных запятыми, его элементы вычисляются слева направо и добавляются в объект-множество. Если задан генератор контейнера, множество создается из элементов, полученных в результате его выполнения.

Пустое множество нельзя создать с помощью {}; этот литерал создает пустой словарь.

6.2.7. Отображения словарей

Отображение словаря — это, возможно, пустая последовательность элементов словаря (пар ключ/значение), заключенная в фигурные скобки:

dict_display       ::= "{" [dict_item_list | dict_comprehension] "}"
dict_item_list     ::= dict_item ("," dict_item)* [","]
dict_item          ::= expression ":" expression | "**" or_expr
dict_comprehension ::= expression ":" expression comp_for

Отображение словаря возвращает новый объект-словарь.

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

Две звездочки ** обозначают распаковку словаря. Операнд должен быть отображением. Каждый элемент отображения добавляется в новый словарь. Более поздние значения заменяют значения, уже заданные предыдущими элементами словаря и предыдущими распаковками словаря.

Добавлено в версии 3.5: Распаковка в отображениях словарей, изначально предложенная в PEP 448.

В отличие от генераторов списков и множеств, генератор словаря требует двух выражений, разделенных двоеточием, за которым следуют обычные части «for» и «if». При выполнении генератора полученные элементы-ключи и элементы-значения вставляются в новый словарь в порядке их появления.

Ограничения на типы значений ключей перечислены выше, в разделе Стандартная иерархия типов. (Кратко говоря, тип ключа должен быть хешируемым, что исключает все изменяемые объекты.) Конфликты между дублирующимися ключами не обнаруживаются; для заданного значения ключа сохраняется последнее значение (крайнее справа в тексте отображения).

Изменено в версии 3.8: До Python 3.8 порядок вычисления ключа и значения в генераторах словарей не был четко определен. В CPython значение вычислялось до ключа. Начиная с версии 3.8, ключ вычисляется до значения, как предложено в PEP 572.

6.2.8. Генераторные выражения

Генераторное выражение — это компактная форма записи генератора в круглых скобках:

generator_expression ::= "(" expression comp_for ")"

Генераторное выражение возвращает новый объект-генератор. Его синтаксис совпадает с синтаксисом генераторов контейнеров, за исключением того, что оно заключается в круглые скобки, а не в квадратные или фигурные.

Переменные, используемые в генераторном выражении, вычисляются лениво при вызове метода __next__() объекта-генератора (так же, как и в обычных генераторах). Однако итерируемое выражение в самой левой части for вычисляется немедленно, поэтому вызванная им ошибка возникнет в месте определения генераторного выражения, а не в момент получения первого значения. Последующие части for и любые условия фильтрации в самой левой части for нельзя вычислить во внешней области видимости, поскольку они могут зависеть от значений, полученных из самой левой итерируемой последовательности. Например: (x*y for x in range(10) for y in range(x, x+10)).

Вызовы с единственным аргументом можно записывать без круглых скобок. Подробности см. в разделе Вызовы.

Чтобы не нарушать ожидаемую работу самого генераторного выражения, выражения yield и yield from запрещены в неявно определяемом генераторе.

Если генераторное выражение содержит части async for или выражения await, оно называется асинхронным генераторным выражением. Асинхронное генераторное выражение возвращает новый объект асинхронного генератора, являющийся асинхронным итератором (см. Асинхронные итераторы).

Добавлено в версии 3.6: Добавлена поддержка асинхронных генераторных выражений.

Изменено в версии 3.7: До Python 3.7 асинхронные генераторные выражения могли использоваться только в корутинах async def. Начиная с версии 3.7 асинхронные генераторные выражения можно использовать в любой функции.

Изменено в версии 3.8: yield и yield from запрещены во вложенной области видимости.

6.2.9. Выражения yield

yield_atom       ::= "(" yield_expression ")"
yield_from       ::= "yield" "from" expression
yield_expression ::= "yield" yield_list | yield_from

Выражение yield используется при определении функции-генератора или функции-асинхронного генератора, поэтому его можно использовать только в теле определения функции. Использование выражения yield в теле функции превращает её в функцию-генератор, а его использование в теле функции async def превращает эту корутинную функцию в функцию-асинхронный генератор. Например:

def gen():  # defines a generator function
    yield 123

async def agen(): # defines an asynchronous generator function
    yield 123

Из-за побочных эффектов в содержащей их области видимости выражения yield нельзя использовать в неявно определённых областях видимости, которые применяются для реализации включений и генераторных выражений.

Изменено в версии 3.8: Выражения yield запрещены в неявно вложенных областях видимости, используемых для реализации включений и генераторных выражений.

Функции-генераторы описаны ниже, а функции-асинхронные генераторы описаны отдельно в разделе Функции-асинхронные генераторы.

При вызове функция-генератор возвращает итератор, называемый генератором. Затем этот генератор управляет выполнением функции-генератора. Выполнение начинается при вызове одного из методов генератора. В этот момент выполнение продолжается до первого выражения yield, где оно снова приостанавливается, возвращая вызывающему коду генератора значение yield_list или None, если yield_list опущено. Под приостановкой подразумевается сохранение всего локального состояния, включая текущие привязки локальных переменных, указатель инструкций, внутренний стек вычислений и состояние любой обработки исключений. Когда выполнение возобновляется вызовом одного из методов генератора, функция может продолжить работу так, словно выражение yield было обычным внешним вызовом. Значение выражения yield после возобновления зависит от метода, который возобновил выполнение. Если используется __next__() (обычно через цикл for или встроенную функцию next()), результатом будет None. Если же используется send(), результатом будет значение, переданное этому методу.

Всё это делает функции-генераторы весьма похожими на корутины: они выдают значения несколько раз, имеют более одной точки входа, и их выполнение может быть приостановлено. Единственное отличие состоит в том, что функция-генератор не может управлять тем, где продолжится выполнение после выдачи значения: управление всегда передаётся вызывающему коду генератора.

Выражения yield разрешены в любом месте конструкции try. Если генератор не возобновить до его завершения (при достижении нулевого счётчика ссылок или сборке мусора), будет вызван метод close() итератора-генератора, что позволит выполнить все ожидающие предложения finally.

При использовании yield from <expr> переданное выражение должно быть итерируемым объектом. Значения, полученные при его переборе, напрямую передаются вызывающему коду методов текущего генератора. Значения, переданные с помощью send(), и исключения, переданные с помощью throw(), передаются базовому итератору, если у него есть соответствующие методы. Если это не так, вызов send() вызовет AttributeError или TypeError, а вызов throw() немедленно вызовет переданное исключение.

Когда базовый итератор завершает работу, атрибут value вызванного экземпляра StopIteration становится значением выражения yield. Его можно задать явно при вызове StopIteration или автоматически, если подчинённый итератор является генератором (путём возврата значения из подгенератора).

Изменено в версии 3.3: Добавлена конструкция yield from <expr> для передачи управления подчинённому итератору.

Скобки можно опустить, если выражение yield является единственным выражением в правой части оператора присваивания.

См. также

PEP 255 — Простые генераторы

Предложение о добавлении генераторов и оператора yield в Python.

PEP 342 — Корутины с помощью усовершенствованных генераторов

Предложение по усовершенствованию API и синтаксиса генераторов, позволяющее использовать их в качестве простых корутин.

PEP 380 — Синтаксис делегирования подгенератору

Предложение о введении синтаксиса yield_from, упрощающего делегирование подгенераторам.

PEP 525 — Асинхронные генераторы

Предложение, развивающее PEP 492 и добавляющее возможности генераторов корутинным функциям.

6.2.9.1. Методы итератора-генератора

В этом подразделе описаны методы итератора-генератора. Их можно использовать для управления выполнением функции-генератора.

Обратите внимание: вызов любого из приведённых ниже методов генератора, когда генератор уже выполняется, вызывает исключение ValueError.

generator.__next__()

Запускает выполнение функции-генератора или возобновляет его с последнего выполненного выражения yield. Когда функция-генератор возобновляется с помощью метода __next__(), текущее выражение yield всегда вычисляется как None. Затем выполнение продолжается до следующего выражения yield, где генератор снова приостанавливается, а значение yield_list возвращается вызывающему коду метода __next__(). Если генератор завершается, не выдав другого значения, вызывается исключение StopIteration.

Обычно этот метод вызывается неявно, например циклом for или встроенной функцией next().

generator.send(value)

Возобновляет выполнение и «отправляет» значение в функцию-генератор. Аргумент value становится результатом текущего выражения yield. Метод send() возвращает следующее значение, выданное генератором, или вызывает StopIteration, если генератор завершается, не выдав другого значения. При вызове send() для запуска генератора аргументом должно быть None, поскольку выражения yield, которое могло бы получить это значение, ещё нет.

generator.throw(value)
generator.throw(type[, value[, traceback]])

Вызывает исключение в точке, в которой генератор был приостановлен, и возвращает следующее значение, выданное функцией-генератором. Если генератор завершается, не выдав другого значения, вызывается исключение StopIteration. Если функция-генератор не перехватывает переданное исключение или вызывает другое исключение, оно передаётся вызывающему коду.

Обычно этот метод вызывается с единственным экземпляром исключения, аналогично использованию ключевого слова raise.

Однако для обратной совместимости поддерживается и вторая сигнатура, соответствующая соглашению из старых версий Python. Аргумент type должен быть классом исключения, а value — экземпляром исключения. Если value не указан, для получения экземпляра вызывается конструктор type. Если указан traceback, он устанавливается в исключении; в противном случае существующий атрибут __traceback__, сохранённый в value, может быть очищен.

Изменено в версии 3.12: Вторая сигнатура (type[, value[, traceback]]) устарела и может быть удалена в будущей версии Python.

generator.close()

Вызывает GeneratorExit в точке, в которой функция-генератор была приостановлена. Если функция-генератор затем завершится штатно, уже закрыта или вызовет GeneratorExit (не перехватив исключение), метод close вернётся к вызывающему коду. Если генератор выдаст значение, будет вызвано исключение RuntimeError. Если генератор вызовет любое другое исключение, оно будет передано вызывающему коду. Метод close() ничего не делает, если генератор уже завершился из-за исключения или штатного завершения.

6.2.9.2. Примеры

Ниже приведён простой пример, демонстрирующий поведение генераторов и функций-генераторов:

>>> def echo(value=None):
...     print("Execution starts when 'next()' is called for the first time.")
...     try:
...         while True:
...             try:
...                 value = (yield value)
...             except Exception as e:
...                 value = e
...     finally:
...         print("Don't forget to clean up when 'close()' is called.")
...
>>> generator = echo(1)
>>> print(next(generator))
Execution starts when 'next()' is called for the first time.
1
>>> print(next(generator))
None
>>> print(generator.send(2))
2
>>> generator.throw(TypeError, "spam")
TypeError('spam',)
>>> generator.close()
Don't forget to clean up when 'close()' is called.

Примеры использования yield from см. в разделе PEP 380: Синтаксис делегирования подгенератору документа «Что нового в Python».

6.2.9.3. Функции-асинхронные генераторы

Наличие выражения yield в функции или методе, определённом с помощью async def, дополнительно определяет эту функцию как функцию-асинхронный генератор.

При вызове функции-асинхронного генератора она возвращает асинхронный итератор, называемый объектом асинхронного генератора. Этот объект управляет выполнением функции-генератора. Обычно объект асинхронного генератора используется в операторе async for внутри корутинной функции, подобно тому как объект генератора используется в операторе for.

Вызов одного из методов асинхронного генератора возвращает объект-объект ожидания, и выполнение начинается, когда этот объект ожидается. В этот момент выполнение продолжается до первого выражения yield, где оно снова приостанавливается, возвращая ожидающей корутине значение yield_list. Как и в случае обычного генератора, приостановка означает сохранение всего локального состояния, включая текущие привязки локальных переменных, указатель инструкций, внутренний стек вычислений и состояние любой обработки исключений. Когда выполнение возобновляется ожиданием следующего объекта, возвращённого методами асинхронного генератора, функция может продолжить работу так, словно выражение yield было обычным внешним вызовом. Значение выражения yield после возобновления зависит от метода, который возобновил выполнение. Если используется __anext__(), результатом будет None. Если же используется asend(), результатом будет значение, переданное этому методу.

Если асинхронный генератор неожиданно завершает работу раньше времени из-за break, отмены задачи вызывающего кода или других исключений, выполняется код асинхронной очистки генератора, который может вызвать исключения или обратиться к контекстным переменным в неожиданном контексте — возможно, уже после завершения задач, от которых он зависит, или во время остановки цикла событий, когда вызывается обработчик сборки мусора асинхронного генератора. Чтобы этого избежать, вызывающий код должен явно закрыть асинхронный генератор, вызвав метод aclose(), чтобы завершить генератор и в конечном итоге отсоединить его от цикла событий.

В функции-асинхронном генераторе выражения yield разрешены в любом месте конструкции try. Однако если асинхронный генератор не возобновить до его завершения (при достижении нулевого счётчика ссылок или сборке мусора), выражение yield внутри конструкции try может помешать выполнению ожидающих предложений finally. В этом случае цикл событий или планировщик, выполняющий асинхронный генератор, должны вызвать метод aclose() итератора-асинхронного генератора и выполнить полученный объект-корутину, чтобы позволить выполнить все ожидающие предложения finally.

Чтобы обеспечить завершение при остановке цикла событий, цикл событий должен определить функцию финализатора, принимающую итератор-асинхронный генератор и, предположительно, вызывающую aclose() и выполняющую корутину. Этот финализатор можно зарегистрировать вызовом sys.set_asyncgen_hooks(). При первой итерации по итератору-асинхронному генератору он сохранит зарегистрированный финализатор, который будет вызван при завершении. Пример реализации метода финализатора см. в реализации asyncio.Loop.shutdown_asyncgens в файле Lib/asyncio/base_events.py.

Выражение yield from <expr> является синтаксической ошибкой при использовании в функции-асинхронном генераторе.

6.2.9.4. Методы итератора-асинхронного генератора

В этом подразделе описаны методы итератора-асинхронного генератора, используемые для управления выполнением функции-генератора.

async agen.__anext__()

Возвращает объект ожидания, выполнение которого запускает асинхронный генератор или возобновляет его с последнего выполненного выражения yield. Когда функция-асинхронный генератор возобновляется с помощью метода __anext__(), текущее выражение yield всегда вычисляется как None в возвращённом объекте ожидания, выполнение которого продолжится до следующего выражения yield. Значение yield_list выражения yield является значением исключения StopIteration, вызванного завершающейся корутиной. Если асинхронный генератор завершает работу, не выдав другого значения, объект ожидания вместо этого вызывает исключение StopAsyncIteration, сигнализирующее о завершении асинхронной итерации.

Обычно этот метод неявно вызывается циклом async for.

async agen.asend(value)

Возвращает объект ожидания, выполнение которого возобновляет работу асинхронного генератора. Как и метод send() обычного генератора, этот метод «отправляет» значение в функцию-асинхронный генератор, а аргумент value становится результатом текущего выражения yield. Объект ожидания, возвращённый методом asend(), возвращает следующее значение, выданное генератором, в качестве значения вызванного исключения StopIteration, либо вызывает StopAsyncIteration, если асинхронный генератор завершает работу, не выдав другого значения. При вызове asend() для запуска асинхронного генератора аргументом должно быть None, поскольку выражения yield, которое могло бы получить это значение, ещё нет.

async agen.athrow(value)
async agen.athrow(type[, value[, traceback]])

Возвращает объект ожидания, который вызывает исключение типа type в точке, в которой асинхронный генератор был приостановлен, и возвращает следующее значение, выданное функцией-генератором, в качестве значения вызванного исключения StopIteration. Если асинхронный генератор завершает работу, не выдав другого значения, объект ожидания вызывает исключение StopAsyncIteration. Если функция-генератор не перехватывает переданное исключение или вызывает другое исключение, при выполнении объекта ожидания это исключение передаётся вызывающему коду.

Изменено в версии 3.12: Вторая сигнатура (type[, value[, traceback]]) устарела и может быть удалена в будущей версии Python.

async agen.aclose()

Возвращает объект ожидания, выполнение которого передаёт GeneratorExit функции-асинхронному генератору в точке, в которой он был приостановлен. Если функция-асинхронный генератор затем завершится штатно, уже закрыта или вызовет GeneratorExit (не перехватив исключение), возвращённый объект ожидания вызовет исключение StopIteration. Любые последующие объекты ожидания, возвращённые следующими вызовами асинхронного генератора, вызовут исключение StopAsyncIteration. Если асинхронный генератор выдаст значение, объект ожидания вызовет исключение RuntimeError. Если асинхронный генератор вызовет любое другое исключение, оно будет передано вызывающему коду объекта ожидания. Если асинхронный генератор уже завершился из-за исключения или штатного завершения, последующие вызовы aclose() вернут объект ожидания, который ничего не делает.

6.3. Первичные выражения

Первичные выражения представляют собой операции языка с наиболее высоким приоритетом. Их синтаксис:

primary ::= atom | attributeref | subscription | slicing | call

6.3.1. Ссылки на атрибуты

Ссылка на атрибут — это первичное выражение, за которым следуют точка и имя:

attributeref ::= primary "." identifier

Первичное выражение должно вычисляться в объект типа, поддерживающего ссылки на атрибуты, как это делают большинство объектов. Затем у этого объекта запрашивается атрибут с именем, указанным идентификатором. Тип и значение получаемого объекта определяются самим объектом. При нескольких вычислениях одной и той же ссылки на атрибут могут получаться разные объекты.

Это поведение можно настроить, переопределив метод __getattribute__() или метод __getattr__(). Сначала вызывается метод __getattribute__(): он либо возвращает значение, либо вызывает исключение AttributeError, если атрибут недоступен.

Если возникает исключение AttributeError и у объекта есть метод __getattr__(), этот метод вызывается в качестве резервного варианта.

6.3.2. Индексация

Индексация экземпляра класса-контейнера обычно выбирает элемент из контейнера. Индексация обобщённого класса обычно возвращает объект GenericAlias.

subscription ::= primary "[" flexible_expression_list "]"

При индексировании объекта интерпретатор вычисляет первичное выражение и список выражений.

Первичное выражение должно вычисляться в объект, поддерживающий индексацию. Объект может поддерживать индексацию, определяя один или оба метода: __getitem__() и __class_getitem__(). При индексировании первичного выражения вычисленный результат списка выражений передаётся одному из этих методов. Подробнее о том, когда вызывается __class_getitem__ вместо __getitem__, см. в разделе __class_getitem__ и __getitem__.

Если список выражений содержит хотя бы одну запятую или любое из выражений отмечено звёздочкой, список выражений вычисляется в tuple, содержащий элементы списка выражений. В противном случае список выражений вычисляется в значение единственного элемента списка.

Изменено в версии 3.11: Выражения в списке выражений могут быть отмечены звёздочкой. См. PEP 646.

Среди встроенных объектов есть два типа объектов, поддерживающих индексацию с помощью __getitem__():

  1. Отображения. Если первичное выражение — это отображение, список выражений должен вычисляться в объект, значение которого является одним из ключей отображения, а индексация выбирает соответствующее этому ключу значение. Пример встроенного класса отображения — класс dict.
  2. Последовательности. Если первичное выражение — это последовательность, список выражений должен вычисляться в int или slice (как описано в следующем разделе). Примеры встроенных классов последовательностей: str, list и tuple.

Формальный синтаксис не предусматривает особой обработки отрицательных индексов в последовательностях. Однако все встроенные последовательности предоставляют метод __getitem__(), который обрабатывает отрицательные индексы, прибавляя к индексу длину последовательности; например, x[-1] выбирает последний элемент x. Полученное значение должно быть неотрицательным целым числом, меньшим количества элементов в последовательности, а индексация выбирает элемент с этим индексом (отсчёт начинается с нуля). Поскольку поддержка отрицательных индексов и срезов реализуется в методе объекта __getitem__(), подклассам, переопределяющим этот метод, необходимо явно добавить такую поддержку.

string — это особый вид последовательности, элементы которой являются символами. Символ не является отдельным типом данных, а представляет собой строку ровно из одного символа.

6.3.3. Срезы

Срез выбирает диапазон элементов объекта-последовательности (например, строки, кортежа или списка). Срезы можно использовать как выражения или как цели в операторах присваивания и del. Синтаксис среза:

slicing      ::= primary "[" slice_list "]"
slice_list   ::= slice_item ("," slice_item)* [","]
slice_item   ::= expression | proper_slice
proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]
lower_bound  ::= expression
upper_bound  ::= expression
stride       ::= expression

В формальном синтаксисе здесь есть неоднозначность: всё, что выглядит как список выражений, также выглядит как список срезов, поэтому любую индексацию можно интерпретировать как срез. Вместо дальнейшего усложнения синтаксиса неоднозначность устраняется правилом, согласно которому в этом случае интерпретация как индексация имеет приоритет над интерпретацией как срез (это происходит, если список срезов не содержит ни одного полноценного среза).

Срезы работают следующим образом. Первичное выражение индексируется (с помощью того же метода __getitem__(), что и при обычной индексации) ключом, сформированным из списка срезов следующим образом. Если список срезов содержит хотя бы одну запятую, ключом является кортеж, содержащий преобразованные элементы среза; в противном случае ключом становится преобразование единственного элемента среза. Элемент среза, представляющий собой выражение, преобразуется в это выражение. Полноценный срез преобразуется в объект-срез (см. раздел Стандартная иерархия типов), атрибуты start, stop и step которого получают значения выражений, заданных в качестве нижней границы, верхней границы и шага соответственно; для отсутствующих выражений подставляется None.

6.3.4. Вызовы

Вызов вызывает вызываемый объект (например, функцию), передавая ему, возможно, пустую последовательность аргументов:

call                 ::= primary "(" [argument_list [","] | comprehension] ")"
argument_list        ::= positional_arguments ["," starred_and_keywords]
                         ["," keywords_arguments]
                         | starred_and_keywords ["," keywords_arguments]
                         | keywords_arguments
positional_arguments ::= positional_item ("," positional_item)*
positional_item      ::= assignment_expression | "*" expression
starred_and_keywords ::= ("*" expression | keyword_item)
                         ("," "*" expression | "," keyword_item)*
keywords_arguments   ::= (keyword_item | "**" expression)
                         ("," keyword_item | "," "**" expression)*
keyword_item         ::= identifier "=" expression

После позиционных и именованных аргументов может следовать завершающая запятая; на семантику она не влияет.

Первичное выражение должно вычисляться в вызываемый объект (вызываемыми являются определённые пользователем функции, встроенные функции, методы встроенных объектов, объекты-классы, методы экземпляров классов и все объекты, имеющие метод __call__()). Все выражения-аргументы вычисляются до попытки вызова. Синтаксис формальных списков параметров см. в разделе Определения функций.

Если присутствуют именованные аргументы, сначала они преобразуются в позиционные следующим образом. Сначала для формальных параметров создаётся список незаполненных ячеек. Если имеется N позиционных аргументов, они помещаются в первые N ячеек. Затем для каждого именованного аргумента идентификатор используется для определения соответствующей ячейки (если идентификатор совпадает с именем первого формального параметра, используется первая ячейка и так далее). Если ячейка уже заполнена, возникает исключение TypeError. В противном случае аргумент помещается в ячейку, заполняя её (даже если выражение — None, ячейка считается заполненной). После обработки всех аргументов оставшиеся незаполненными ячейки заполняются соответствующими значениями по умолчанию из определения функции. (Значения по умолчанию вычисляются один раз — при определении функции; поэтому изменяемый объект, например список или словарь, используемый в качестве значения по умолчанию, будет общим для всех вызовов, не указывающих значение аргумента для соответствующей ячейки; обычно этого следует избегать.) Если остались незаполненные ячейки, для которых не задано значение по умолчанию, возникает исключение TypeError. В противном случае список заполненных ячеек используется в качестве списка аргументов вызова.

Особенность реализации CPython: Реализация может предоставлять встроенные функции, позиционные параметры которых не имеют имён, даже если для целей документации они «именованы», и поэтому их нельзя передать как именованные аргументы. В CPython это относится к функциям, реализованным на C, которые используют PyArg_ParseTuple() для разбора аргументов.

Если позиционных аргументов больше, чем ячеек формальных параметров, возникает исключение TypeError, если только не указан формальный параметр с синтаксисом *identifier; в этом случае этот формальный параметр получает кортеж с избыточными позиционными аргументами (или пустой кортеж, если избыточных позиционных аргументов нет).

Если какой-либо именованный аргумент не соответствует имени формального параметра, возникает исключение TypeError, если только не указан формальный параметр с синтаксисом **identifier; в этом случае этот формальный параметр получает словарь с избыточными именованными аргументами (ключами служат имена аргументов, а значениями — соответствующие значения аргументов) или новый пустой словарь, если избыточных именованных аргументов нет.

Если в вызове функции используется синтаксис *expression, выражение expression должно вычисляться в итерируемый объект. Элементы этих итерируемых объектов обрабатываются как дополнительные позиционные аргументы. Для вызова f(x1, x2, *y, x3, x4), если y вычисляется в последовательность y1, …, yM, это эквивалентно вызову с M+4 позиционными аргументами x1, x2, y1, …, yM, x3, x4.

Отсюда следует, что хотя синтаксис *expression может располагаться после явных именованных аргументов, он обрабатывается до именованных аргументов (и любых аргументов **expression — см. ниже). Поэтому:

>>> def f(a, b):
...     print(a, b)
...
>>> f(b=1, *(2,))
2 1
>>> f(a=1, *(2,))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() got multiple values for keyword argument 'a'
>>> f(1, *(2,))
1 2

Совместное использование именованных аргументов и синтаксиса *expression в одном вызове встречается редко, поэтому на практике такая путаница возникает нечасто.

Если в вызове функции используется синтаксис **expression, выражение expression должно вычисляться в отображение, содержимое которого обрабатывается как дополнительные именованные аргументы. Если параметру, соответствующему ключу, уже присвоено значение (явным именованным аргументом или при распаковке другого отображения), возникает исключение TypeError.

При использовании **expression каждый ключ в этом отображении должен быть строкой. Каждое значение из отображения присваивается первому формальному параметру, которому можно назначить именованный аргумент и имя которого совпадает с ключом. Ключ не обязан быть идентификатором Python (например, "max-temp °F" допустимо, хотя оно не совпадёт ни с одним формальным параметром, который можно объявить). Если соответствующего формального параметра нет, пара ключ-значение собирается параметром **, если он есть; иначе возникает исключение TypeError.

Формальные параметры с синтаксисом *identifier или **identifier нельзя использовать как ячейки для позиционных аргументов или как имена именованных аргументов.

Изменено в версии 3.5: Вызовы функций принимают любое количество распаковок * и **; позиционные аргументы могут следовать за распаковками итерируемых объектов (*), а именованные аргументы — за распаковками словарей (**). Изначально предложено в PEP 448.

Вызов всегда возвращает некоторое значение, возможно, None, если только не возникает исключение. Способ вычисления этого значения зависит от типа вызываемого объекта.

Если это —

функция, определённая пользователем:

Выполняется блок кода функции с передачей ему списка аргументов. Первым делом блок кода связывает формальные параметры с аргументами; это описано в разделе Определения функций. Когда блок кода выполняет оператор return, он задаёт возвращаемое значение вызова функции. Если выполнение достигает конца блока кода, не выполнив оператор return, возвращаемым значением становится None.

встроенная функция или метод:

Результат определяется интерпретатором; описания встроенных функций и методов см. в разделе Встроенные функции.

объект-класс:

Возвращается новый экземпляр этого класса.

метод экземпляра класса:

Вызывается соответствующая функция, определённая пользователем, со списком аргументов, который на один элемент длиннее списка аргументов вызова: экземпляр становится первым аргументом.

экземпляр класса:

Класс должен определять метод __call__(); тогда результат будет таким же, как если бы был вызван этот метод.

6.4. Выражение await

Приостанавливает выполнение сопрограммы в ожидании объекта awaitable. Может использоваться только внутри функции-сопрограммы.

await_expr ::= "await" primary

Добавлено в версии 3.5.

6.5. Оператор возведения в степень

Оператор возведения в степень имеет более высокий приоритет, чем унарные операторы слева от него, и более низкий, чем унарные операторы справа от него. Синтаксис:

power ::= (await_expr | primary) ["**" u_expr]

Таким образом, в непомещённой в скобки последовательности операторов возведения в степень и унарных операторов вычисление выполняется справа налево (это не ограничивает порядок вычисления операндов): -1**2 даёт результат -1.

Оператор возведения в степень имеет ту же семантику, что и встроенная функция pow(), вызванная с двумя аргументами: он возводит левый аргумент в степень правого. Сначала числовые аргументы приводятся к общему типу, и результат имеет этот тип.

Для операндов типа int результат имеет тот же тип, что и операнды, если только второй аргумент не отрицательный; в этом случае все аргументы преобразуются в float и возвращается результат типа float. Например, 10**2 возвращает 100, а 10**-2 возвращает 0.01.

Возведение 0.0 в отрицательную степень вызывает исключение ZeroDivisionError. Возведение отрицательного числа в дробную степень даёт число типа complex. (В более ранних версиях возникало исключение ValueError.)

Эту операцию можно настроить с помощью специальных методов __pow__() и __rpow__().

6.6. Унарные арифметические и побитовые операции

Все унарные арифметические и побитовые операции имеют одинаковый приоритет:

u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr

Унарный оператор - (минус) возвращает отрицательное значение своего числового аргумента; эту операцию можно переопределить специальным методом __neg__().

Унарный оператор + (плюс) возвращает числовой аргумент без изменений; эту операцию можно переопределить специальным методом __pos__().

Унарный оператор ~ (инверсия) возвращает побитовую инверсию целочисленного аргумента. Побитовая инверсия x определяется как -(x+1). Оператор применим только к целым числам или пользовательским объектам, переопределяющим специальный метод __invert__().

Во всех трёх случаях, если аргумент имеет неподходящий тип, возникает исключение TypeError.

6.7. Бинарные арифметические операции

Бинарные арифметические операции имеют традиционные уровни приоритета. Обратите внимание, что некоторые из них применимы также к определённым нечисловым типам. Помимо оператора возведения в степень, есть только два уровня: один для операторов умножения и деления, другой — для операторов сложения и вычитания:

m_expr ::= u_expr | m_expr "*" u_expr | m_expr "@" m_expr |
           m_expr "//" u_expr | m_expr "/" u_expr |
           m_expr "%" u_expr
a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr

Оператор * (умножение) возвращает произведение своих аргументов. Аргументы должны быть либо оба числами, либо один аргумент должен быть целым числом, а другой — последовательностью. В первом случае числа приводятся к общему типу и перемножаются. Во втором случае выполняется повторение последовательности; отрицательный множитель даёт пустую последовательность.

Эту операцию можно настроить с помощью специальных методов __mul__() и __rmul__().

Оператор @ (at) предназначен для умножения матриц. Ни один встроенный тип Python не реализует этот оператор.

Эту операцию можно настроить с помощью специальных методов __matmul__() и __rmatmul__().

Добавлено в версии 3.5.

Операторы / (деление) и // (целочисленное деление с округлением вниз) возвращают частное от деления своих аргументов. Сначала числовые аргументы приводятся к общему типу. Деление целых чисел даёт число с плавающей точкой, а целочисленное деление целых чисел — целое число; результат соответствует математическому делению с применением к результату функции «floor». Деление на ноль вызывает исключение ZeroDivisionError.

Операцию деления можно настроить с помощью специальных методов __truediv__() и __rtruediv__(). Операцию целочисленного деления можно настроить с помощью специальных методов __floordiv__() и __rfloordiv__().

Оператор % (остаток от деления) возвращает остаток от деления первого аргумента на второй. Сначала числовые аргументы приводятся к общему типу. Если правый аргумент равен нулю, возникает исключение ZeroDivisionError. Аргументы могут быть числами с плавающей точкой, например, 3.14%0.7 равно 0.34 (поскольку 3.14 равно 4*0.7 + 0.34). Оператор остатка всегда возвращает результат с тем же знаком, что и второй операнд (или ноль); абсолютное значение результата строго меньше абсолютного значения второго операнда [1].

Операторы целочисленного деления и остатка связаны следующим тождеством: x == (x//y)*y + (x%y). Целочисленное деление и остаток также связаны со встроенной функцией divmod(): divmod(x, y) == (x//y, x%y). [2].

Помимо вычисления остатка от деления чисел, оператор % также перегружен строковыми объектами для форматирования строк в старом стиле (также известного как интерполяция). Синтаксис форматирования строк описан в Справочнике по стандартной библиотеке Python, в разделе Форматирование строк в стиле printf.

Операцию остатка от деления можно настроить с помощью специальных методов __mod__() и __rmod__().

Оператор целочисленного деления, оператор остатка и функция divmod() не определены для комплексных чисел. Вместо этого при необходимости преобразуйте число в число с плавающей точкой с помощью функции abs().

Оператор + (сложение) возвращает сумму своих аргументов. Аргументы должны быть либо оба числами, либо последовательностями одного типа. В первом случае числа приводятся к общему типу и складываются. Во втором случае последовательности конкатенируются.

Эту операцию можно настроить с помощью специальных методов __add__() и __radd__().

Оператор - (вычитание) возвращает разность своих аргументов. Сначала числовые аргументы приводятся к общему типу.

Эту операцию можно настроить с помощью специальных методов __sub__() и __rsub__().

6.8. Операции сдвига

Операции сдвига имеют более низкий приоритет, чем арифметические операции:

shift_expr ::= a_expr | shift_expr ("<<" | ">>") a_expr

Эти операторы принимают целые числа в качестве аргументов. Они сдвигают первый аргумент влево или вправо на количество битов, указанное вторым аргументом.

Операцию сдвига влево можно настроить с помощью специальных методов __lshift__() и __rlshift__(). Операцию сдвига вправо можно настроить с помощью специальных методов __rshift__() и __rrshift__().

Сдвиг вправо на n битов определяется как целочисленное деление с округлением вниз на pow(2,n). Сдвиг влево на n битов определяется как умножение на pow(2,n).

6.9. Двоичные побитовые операции

У каждой из трёх побитовых операций свой уровень приоритета:

and_expr ::= shift_expr | and_expr "&" shift_expr
xor_expr ::= and_expr | xor_expr "^" and_expr
or_expr  ::= xor_expr | or_expr "|" xor_expr

Оператор & выполняет побитовое И для своих аргументов, которые должны быть целыми числами, либо один из них должен быть пользовательским объектом, переопределяющим специальные методы __and__() или __rand__().

Оператор ^ выполняет побитовое исключающее ИЛИ (XOR) для своих аргументов, которые должны быть целыми числами, либо один из них должен быть пользовательским объектом, переопределяющим специальные методы __xor__() или __rxor__().

Оператор | выполняет побитовое (включающее) ИЛИ для своих аргументов, которые должны быть целыми числами, либо один из них должен быть пользовательским объектом, переопределяющим специальные методы __or__() или __ror__().

6.10. Сравнения

В отличие от C, все операции сравнения в Python имеют одинаковый приоритет, который ниже приоритета любых арифметических операций, операций сдвига и побитовых операций. Кроме того, в отличие от C, выражения вроде a < b < c интерпретируются так, как это принято в математике:

comparison    ::= or_expr (comp_operator or_expr)*
comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="
                  | "is" ["not"] | ["not"] "in"

Результатом сравнений являются логические значения: True или False. Пользовательские методы расширенного сравнения могут возвращать значения, не являющиеся логическими. В этом случае Python вызывает для такого значения bool() в логическом контексте.

Сравнения можно объединять в цепочки произвольной длины. Например, x < y <= z эквивалентно x < y and y <= z, за исключением того, что y вычисляется только один раз (но в обоих случаях z вообще не вычисляется, если x < y оказывается ложным).

Формально, если a, b, c, …, y, z — выражения, а op1, op2, …, opN — операторы сравнения, то a op1 b op2 c ... y opN z эквивалентно a op1 b and b op2 c and ... y opN z, за исключением того, что каждое выражение вычисляется не более одного раза.

Обратите внимание: a op1 b op2 c не подразумевает сравнения какого-либо рода между a и c, поэтому, например, x < y > z вполне допустимо (хотя, возможно, выглядит не слишком изящно).

6.10.1. Сравнение значений

Операторы <, >, ==, >=, <= и != сравнивают значения двух объектов. Объекты не обязаны иметь одинаковый тип.

В главе Объекты, значения и типы указано, что у объектов есть значение (помимо типа и идентичности). В Python значение объекта — довольно абстрактное понятие: например, для объекта не существует общепринятого способа доступа к его значению. Также нет требования, чтобы значение объекта формировалось каким-либо определённым способом, например состояло из всех его атрибутов данных. Операторы сравнения реализуют определённое представление о том, что такое значение объекта. Можно считать, что они косвенно определяют значение объекта посредством реализации сравнения.

Поскольку все типы являются прямыми или косвенными подтипами object, они наследуют поведение сравнения по умолчанию от object. Типы могут настраивать поведение сравнения, реализуя методы расширенного сравнения, такие как __lt__(), описанный в разделе Базовая настройка.

Поведение сравнения на равенство по умолчанию (== и !=) основано на идентичности объектов. Следовательно, сравнение на равенство экземпляров с одинаковой идентичностью даёт равенство, а экземпляров с разной идентичностью — неравенство. Одно из обоснований такого поведения по умолчанию — желание обеспечить рефлексивность всех объектов (то есть из x is y следует x == y).

Сравнение на порядок по умолчанию (<, >, <= и >=) не предусмотрено; попытка его выполнить приводит к возникновению исключения TypeError. Причина такого поведения по умолчанию — отсутствие инварианта, аналогичного инварианту для равенства.

Поведение сравнения на равенство по умолчанию, при котором экземпляры с разной идентичностью всегда считаются неравными, может не соответствовать требованиям типов, для которых существует разумное определение значения объекта и сравнения по значению. Такие типы должны настраивать поведение сравнения; некоторые встроенные типы уже это делают.

В следующем списке описано поведение сравнения для наиболее важных встроенных типов.

  • Числа встроенных числовых типов (Числовые типы — int, float, complex) и стандартных библиотечных типов fractions.Fraction и decimal.Decimal можно сравнивать как внутри одного типа, так и между типами, с тем ограничением, что комплексные числа не поддерживают сравнение на порядок. В пределах возможностей участвующих типов сравнения выполняются математически (алгоритмически) корректно, без потери точности.

    Значения «не число» float('NaN') и decimal.Decimal('NaN') являются особыми. Любое упорядоченное сравнение числа со значением «не число» даёт результат «ложь». Неочевидное следствие этого состоит в том, что значения «не число» не равны самим себе. Например, если x = float('NaN'), 3 < x, x < 3 и x == x, все они ложны, а x != x истинно. Такое поведение соответствует стандарту IEEE 754.

  • None и NotImplemented — одиночки. PEP 8 рекомендует всегда проверять одиночки с помощью is или is not, а не операторов сравнения на равенство.
  • Двоичные последовательности (экземпляры bytes или bytearray) можно сравнивать как внутри одного типа, так и между типами. Сравнение выполняется лексикографически с использованием числовых значений элементов.
  • Строки (экземпляры str) сравниваются лексикографически с использованием числовых кодовых точек Unicode символов (результата встроенной функции ord()). [3]

    Строки и двоичные последовательности нельзя сравнивать напрямую.

  • Последовательности (экземпляры tuple, list или range) можно сравнивать только внутри каждого из этих типов; при этом диапазоны не поддерживают сравнение на порядок. Сравнение на равенство между этими типами даёт неравенство, а сравнение на порядок между ними вызывает исключение TypeError.

    Последовательности сравниваются лексикографически, путём сравнения соответствующих элементов. Встроенные контейнеры обычно предполагают, что идентичные объекты равны сами себе. Это позволяет им пропускать проверки на равенство идентичных объектов, повышая производительность и сохраняя внутренние инварианты.

    Лексикографическое сравнение встроенных коллекций выполняется следующим образом:

    • Чтобы две коллекции считались равными, они должны иметь одинаковый тип, одинаковую длину, а каждая пара соответствующих элементов должна быть равна (например, [1,2] == (1,2) ложно, поскольку типы различаются).
    • Коллекции, поддерживающие сравнение на порядок, упорядочиваются так же, как их первые неравные элементы (например, [1,2,x] <= [1,2,y] имеет то же значение, что и x <= y). Если соответствующий элемент отсутствует, первой считается более короткая коллекция (например, [1,2] < [1,2,3] истинно).
  • Отображения (экземпляры dict) равны тогда и только тогда, когда у них совпадают пары (key, value). Сравнение ключей и значений на равенство обеспечивает рефлексивность.

    Сравнения на порядок (<, >, <= и >=) вызывают исключение TypeError.

  • Множества (экземпляры set или frozenset) можно сравнивать как внутри одного типа, так и между типами.

    Операторы сравнения на порядок для множеств означают проверку отношений подмножества и надмножества. Эти отношения не задают линейный порядок (например, два множества {1,2} и {2,3} не равны, и ни одно из них не является подмножеством или надмножеством другого). Поэтому множества не подходят в качестве аргументов для функций, зависящих от линейного порядка (например, min(), max() и sorted() дают неопределённые результаты, если в качестве входных данных передан список множеств).

    Сравнение множеств обеспечивает рефлексивность их элементов.

  • Для большинства других встроенных типов методы сравнения не реализованы, поэтому они наследуют поведение сравнения по умолчанию.

Пользовательским классам, настраивающим поведение сравнения, по возможности следует соблюдать некоторые правила согласованности:

  • Сравнение на равенство должно быть рефлексивным. Иными словами, идентичные объекты должны считаться равными:

    x is y влечёт x == y

  • Сравнение должно быть симметричным. Иными словами, следующие выражения должны давать одинаковый результат:

    x == y и y == x

    x != y и y != x

    x < y и y > x

    x <= y и y >= x

  • Сравнение должно быть транзитивным. Следующие примеры (не исчерпывающий список) это иллюстрируют:

    x > y and y > z влечёт x > z

    x < y and y <= z влечёт x < z

  • Обратное сравнение должно давать логическое отрицание. Иными словами, следующие выражения должны давать одинаковый результат:

    x == y и not x != y

    x < y и not x >= y (для линейного порядка)

    x > y и not x <= y (для линейного порядка)

    Последние два выражения применимы к коллекциям с линейным порядком (например, к последовательностям, но не к множествам или отображениям). См. также декоратор total_ordering().

  • Результат hash() должен согласовываться с равенством. Равные объекты должны иметь одинаковое хеш-значение либо быть помечены как нехешируемые.

Python не обеспечивает соблюдение этих правил согласованности. В частности, значения «не число» служат примером их несоблюдения.

6.10.2. Проверка принадлежности

Операторы in и not in проверяют принадлежность. x in s вычисляется в значение True, если x является элементом s, и в False в противном случае. x not in s возвращает логическое отрицание x in s. Все встроенные последовательности и типы множеств поддерживают эту операцию, как и словари, для которых in проверяет, содержит ли словарь заданный ключ. Для таких контейнерных типов, как list, tuple, set, frozenset, dict или collections.deque, выражение x in y эквивалентно any(x is e or x == e for e in y).

Для строк и байтовых последовательностей x in y имеет значение True тогда и только тогда, когда x является подстрокой y. Эквивалентная проверка: y.find(x) != -1. Пустые строки всегда считаются подстроками любой другой строки, поэтому "" in "abc" вернёт True.

Для пользовательских классов, определяющих метод __contains__(), x in y возвращает True, если y.__contains__(x) возвращает истинное значение, и False в противном случае.

Для пользовательских классов, не определяющих __contains__(), но определяющих __iter__(), x in y имеет значение True, если при итерации по y получается некоторое значение z, для которого выражение x is z or x == z истинно. Если во время итерации возникает исключение, это равносильно тому, что in вызвал это исключение.

Наконец, проверяется протокол итерации старого стиля: если класс определяет __getitem__(), x in y имеет значение True тогда и только тогда, когда существует неотрицательный целочисленный индекс i, для которого выполняется x is y[i] or x == y[i], и ни один меньший целочисленный индекс не вызывает исключение IndexError. (Если возникает любое другое исключение, это равносильно тому, что in вызвал это исключение.)

Оператор not in определён как оператор, возвращающий значение, противоположное логическому значению in.

6.10.3. Проверка идентичности

Операторы is и is not проверяют идентичность объектов: x is y истинно тогда и только тогда, когда x и y — один и тот же объект. Идентичность объекта определяется с помощью функции id(). x is not y возвращает противоположное логическое значение. [4]

6.11. Логические операции

or_test  ::= and_test | or_test "or" and_test
and_test ::= not_test | and_test "and" not_test
not_test ::= comparison | "not" not_test

В контексте логических операций, а также когда выражения используются в операторах управления потоком, следующие значения интерпретируются как ложные: False, None, числовой ноль всех типов, а также пустые строки и контейнеры (включая строки, кортежи, списки, словари, множества и неизменяемые множества). Все остальные значения интерпретируются как истинные. Пользовательские объекты могут настраивать своё логическое значение, предоставляя метод __bool__().

Оператор not возвращает True, если его аргумент ложен, и False в противном случае.

Выражение x and y сначала вычисляет x; если x ложно, возвращается его значение; в противном случае вычисляется y и возвращается полученное значение.

Выражение x or y сначала вычисляет x; если x истинно, возвращается его значение; в противном случае вычисляется y и возвращается полученное значение.

Обратите внимание: ни and, ни or не ограничивают возвращаемые значения и типы значениями False и True, а возвращают последний вычисленный аргумент. Это иногда полезно: например, если s — строка, которую следует заменить значением по умолчанию, когда она пуста, выражение s or 'foo' возвращает нужное значение. Поскольку not должен создать новое значение, он возвращает логическое значение независимо от типа аргумента (например, not 'foo' даёт False, а не '').

6.12. Выражения присваивания

assignment_expression ::= [identifier ":="] expression

Выражение присваивания (иногда также называемое «именованным выражением» или «моржом») присваивает expression идентификатору identifier и одновременно возвращает значение expression.

Один из распространённых вариантов использования — обработка совпадений с регулярными выражениями:

if matching := pattern.search(data):
    do_something(matching)

Другой пример — чтение файла потоком по частям:

while chunk := file.read(9000):
    process(chunk)

Выражения присваивания необходимо заключать в скобки, если они используются как выражения-операторы или как подвыражения в выражениях для срезов, условных выражениях, лямбда-выражениях, выражениях с ключевыми аргументами и выражениях фильтрации в включениях, а также в операторах assert, with и assignment. Во всех остальных случаях, где их можно использовать, скобки не требуются, в том числе в операторах if и while.

Добавлено в версии 3.8: Подробнее о выражениях присваивания см. в PEP 572.

6.13. Условные выражения

conditional_expression ::= or_test ["if" or_test "else" expression]
expression             ::= conditional_expression | lambda_expr

Условные выражения (иногда называемые «тернарным оператором») имеют самый низкий приоритет среди всех операций Python.

Выражение x if C else y сначала вычисляет условие C, а не x. Если C истинно, вычисляется x и возвращается его значение; в противном случае вычисляется y и возвращается его значение.

Подробнее об условных выражениях см. в PEP 308.

6.14. Лямбда-выражения

lambda_expr ::= "lambda" [parameter_list] ":" expression

Лямбда-выражения (иногда называемые лямбда-формами) используются для создания анонимных функций. Выражение lambda parameters: expression возвращает объект-функцию. Этот объект без имени ведёт себя как объект-функция, определённый с помощью:

def <lambda>(parameters):
    return expression

Синтаксис списков параметров описан в разделе Определения функций. Обратите внимание, что функции, созданные с помощью лямбда-выражений, не могут содержать операторы или аннотации.

6.15. Списки выражений

starred_expression       ::= ["*"] or_expr
flexible_expression      ::= assignment_expression | starred_expression
flexible_expression_list ::= flexible_expression ("," flexible_expression)* [","]
starred_expression_list  ::= starred_expression ("," starred_expression)* [","]
expression_list          ::= expression ("," expression)* [","]
yield_list               ::= expression_list | starred_expression "," [starred_expression_list]

Если список выражений, содержащий хотя бы одну запятую, не является частью отображения списка или множества, он возвращает кортеж. Длина кортежа равна количеству выражений в списке. Выражения вычисляются слева направо.

Звёздочка * обозначает распаковку итерируемого объекта. Её операнд должен быть итерируемым объектом. Итерируемый объект раскрывается в последовательность элементов, которые включаются в новый кортеж, список или множество в месте распаковки.

Добавлено в версии 3.5: Распаковка итерируемых объектов в списках выражений, изначально предложенная в PEP 448.

Добавлено в версии 3.11: Любой элемент списка выражений может иметь перед собой звёздочку. См. PEP 646.

Завершающая запятая нужна только для создания кортежа из одного элемента, например 1,; во всех остальных случаях она необязательна. Одиночное выражение без завершающей запятой не создаёт кортеж, а возвращает значение этого выражения. (Чтобы создать пустой кортеж, используйте пустую пару круглых скобок: ().)

6.16. Порядок вычисления

Python вычисляет выражения слева направо. Обратите внимание: при вычислении присваивания правая часть вычисляется раньше левой.

В следующих строках выражения будут вычисляться в арифметическом порядке, соответствующем их суффиксам:

expr1, expr2, expr3, expr4
(expr1, expr2, expr3, expr4)
{expr1: expr2, expr3: expr4}
expr1 + expr2 * (expr3 - expr4)
expr1(expr2, expr3, *expr4, **expr5)
expr3, expr4 = expr1, expr2

6.17. Приоритет операторов

В следующей таблице приведён сводный порядок приоритета операторов Python: от наивысшего (наиболее сильное связывание) до наименьшего (наименее сильное связывание). Операторы в одной ячейке имеют одинаковый приоритет. Если синтаксис не указан явно, операторы являются бинарными. Операторы в одной ячейке группируются слева направо (за исключением возведения в степень и условных выражений, которые группируются справа налево).

Обратите внимание, что сравнения, проверки вхождения и проверки идентичности имеют одинаковый приоритет и поддерживают цепочки слева направо, как описано в разделе Сравнения.

Оператор

Описание

(expressions...),

[expressions...], {key: value...}, {expressions...}

Группировка или выражение в скобках, отображение списка, отображение словаря, отображение множества

x[index], x[index:index], x(arguments...), x.attribute

Индексация, срез, вызов, ссылка на атрибут

await x

Выражение await

**

Возведение в степень [5]

+x, -x, ~x

Положительное значение, отрицательное значение, побитовое НЕ

*, @, /, //, %

Умножение, умножение матриц, деление, целочисленное деление с округлением вниз, остаток [6]

+, -

Сложение и вычитание

<<, >>

Сдвиги

&

Побитовое И

^

Побитовое исключающее ИЛИ

|

Побитовое ИЛИ

in, not in, is, is not, <, <=, >, >=, !=, ==

Сравнения, включая проверки вхождения и проверки идентичности

not x

Логическое НЕ

and

Логическое И

or

Логическое ИЛИ

if – else

Условное выражение

lambda

Лямбда-выражение

:=

Выражение присваивания

Сноски

[1]

Хотя abs(x%y) < abs(y) верно с математической точки зрения, для чисел с плавающей точкой это может быть неверно с численной точки зрения из-за ошибок округления. Например, если предположить, что платформа использует числа Python с плавающей точкой в формате IEEE 754 двойной точности, то, чтобы -1e-100 % 1e100 имело тот же знак, что и 1e100, вычисленный результат равен -1e-100 + 1e100, что численно в точности равно 1e100. Функция math.fmod() возвращает результат, знак которого совпадает со знаком первого аргумента, поэтому в данном случае она возвращает -1e-100. Выбор подхода зависит от конкретного приложения.

[2]

Если x очень близко к точному целому кратному y, из-за округления x//y может быть на единицу больше, чем (x-x%y)//y. В таких случаях Python возвращает второй результат, чтобы сохранить условие, что divmod(x,y)[0] * y + x % y должно быть очень близко к x.

[3]

Стандарт Unicode различает кодовые точки (например, U+0041) и абстрактные символы (например, «LATIN CAPITAL LETTER A»). Хотя большинство абстрактных символов Unicode представлены только одной кодовой точкой, некоторые абстрактные символы могут также представляться последовательностью из нескольких кодовых точек. Например, абстрактный символ «LATIN CAPITAL LETTER C WITH CEDILLA» может быть представлен одним составным символом в позиции U+00C7 или последовательностью из базового символа в позиции U+0043 (LATIN CAPITAL LETTER C), за которым следует комбинируемый символ в позиции U+0327 (COMBINING CEDILLA).

Операторы сравнения строк сравнивают строки на уровне кодовых точек Unicode. Для людей это может быть неочевидно. Например, "\u00C7" == "\u0043\u0327" не равно False, хотя обе строки представляют один и тот же абстрактный символ «LATIN CAPITAL LETTER C WITH CEDILLA».

Чтобы сравнивать строки на уровне абстрактных символов (то есть интуитивно понятным для людей способом), используйте unicodedata.normalize().

[4]

Из-за автоматической сборки мусора, списков свободных объектов и динамической природы дескрипторов при некоторых способах использования оператора is можно заметить на первый взгляд необычное поведение, например при сравнении методов экземпляров или констант. Дополнительную информацию см. в документации к ним.

[5]

Оператор возведения в степень ** имеет более низкий приоритет, чем арифметический или побитовый унарный оператор справа от него, то есть 2**-1 — это 0.5.

[6]

Оператор % также используется для форматирования строк; при этом применяется тот же приоритет.

© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/reference/expressions.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API