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 ::=  "[" [starred_list | comprehension] "]"

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

6.2.6. Представления множеств

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

set_display ::=  "{" (starred_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" expression_list | yield_from

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

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

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

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

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

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

Когда вызывается функция-генератор, она возвращает итератор, известный как генератор. Затем этот генератор управляет выполнением функции-генератора. Выполнение начинается, когда вызывается один из методов генератора. В этот момент выполнение продолжается до первого выражения yield, где оно приостанавливается, возвращая значение expression_list вызывающей функции-генератора, или None если expression_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, где генератор снова приостанавливается, а значение expression_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.

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

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

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

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

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

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

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

coroutine agen.__anext__()

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

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

coroutine agen.asend(value)

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

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

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

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

coroutine agen.aclose()

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

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 "[" expression_list "]"

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

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

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

Для встроенных объектов существуют два типа объектов, поддерживающих подписку через __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, это указывает возвращаемое значение вызова функции.

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

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

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

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

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

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

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

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

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

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

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__().

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

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

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

Операторы / (деление) и // (целочисленное деление) возвращают частное от деления своих аргументов. Числовые аргументы сначала преобразуются к общему типу. Деление целых чисел возвращает вещественное число, а целочисленное деление целых чисел приводит к целому числу; результат соответствует математическому делению с применением функции «округления вниз» к результату. Деление на ноль вызывает исключение 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) сравниваются лексикографически с использованием числовых кодов Юникода (результат встроенной функции 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 проверяет наличие заданного ключа. Для контейнерных типов, таких как список, кортеж, множество, неизменяемое множество, словарь или очередь 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 возвращает False если его аргумент ложный, True в противном случае.

Выражение 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

Выражение присваивания (иногда также называемое «именованным выражением» или «выражением walrus») присваивает 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. Списки выражений

expression_list    ::=  expression ("," expression)* [","]
starred_list       ::=  starred_item ("," starred_item)* [","]
starred_expression ::=  expression | (starred_item ",")* [starred_item]
starred_item       ::=  assignment_expression | "*" or_expr

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

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

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

Конечная запятая требуется только для создания кортежа из одного элемента, такого как 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 float является числом двойной точности 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-x%y)//y.

[3]

Стандарт Unicode различает кодовые точки (например, U+0041) и абстрактные символы (например, “ЛАТИНСКАЯ ПРОПИСНАЯ БУКВА A”). Хотя большинство абстрактных символов в Unicode представлены только одной кодовой точкой, существует ряд абстрактных символов, которые могут дополнительно представляться последовательностью более одной кодовой точки. Например, абстрактный символ “ЛАТИНСКАЯ ПРОПИСНАЯ БУКВА С С ЦЕДЬЮ” может быть представлен как единый прекомпонованный символ в позиции кода U+00C7 или как последовательность основного символа в позиции кода U+0043 (ЛАТИНСКАЯ ПРОПИСНАЯ БУКВА С), за которым следует комбинирующий символ в позиции кода U+0327 (КОМБИНИРУЮЩАЯ ЦЕДЬ).

Операторы сравнения для строк сравнивают на уровне кодовых точек Unicode. Это может быть неинтуитивно для человека. Например, "\u00C7" == "\u0043\u0327" равно False, даже если обе строки представляют один и тот же абстрактный символ “ЛАТИНСКАЯ ПРОПИСНАЯ БУКВА С С ЦЕДЬЮ”.

Для сравнения строк на уровне абстрактных символов (то есть интуитивно для человека) используйте 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