Выражения
В этой главе объясняется значение элементов выражений в Python.
Примечания по синтаксису: В этой и следующих главах для описания синтаксиса, а не лексического анализа, будет использоваться грамматическая нотация.
Если (один из вариантов) синтаксического правила имеет вид:
name: othername
и семантика не указана, семантика этой формы name совпадает с семантикой othername.
6.1. Арифметические преобразования
Когда в приведённом ниже описании арифметического оператора используется фраза «числовые аргументы преобразуются к общему вещественному типу», это означает, что реализация оператора для встроенных числовых типов работает так, как описано в разделе Числовые типы документации стандартной библиотеки.
Для некоторых операторов и нечисловых операндов действуют дополнительные правила (например, строка в качестве левого аргумента оператора %). Расширения должны определять собственное поведение преобразования.
6.2. Атомы
Атомы — самые простые элементы выражений. Простейшие атомы — это имена или литералы. Формы, заключённые в круглые, квадратные или фигурные скобки, также синтаксически относятся к атомам.
Формально синтаксис атомов выглядит так:
atom: | 'True' | 'False' | 'None' | '...' | identifier | literal | enclosure enclosure: | parenth_form | list_display | dict_display | set_display | generator_expression | yield_atom
6.2.1. Встроенные константы
Ключевые слова True, False и None обозначают встроенные константы. Токен ... обозначает константу Ellipsis.
Вычисление этих атомов даёт соответствующее значение.
Примечание
В качестве глобальных переменных доступны и другие встроенные константы, но только перечисленные здесь являются ключевыми словами. В частности, этим именам нельзя присваивать значения и использовать их в качестве атрибутов:
>>> False = 123 File "<input>", line 1 False = 123 ^^^^^ SyntaxError: cannot assign to False
6.2.2. Идентификаторы (имена)
Идентификатор, встречающийся в качестве атома, является именем. Лексическое определение приведено в разделе Имена (идентификаторы и ключевые слова), а описание присваивания имён и связывания — в разделе Именование и связывание.
Если имя связано с объектом, вычисление атома даёт этот объект. Если имя не связано с объектом, попытка его вычисления вызывает исключение NameError.
6.2.2.1. Преобразование приватных имён
Если идентификатор, текстуально встречающийся в определении класса, начинается с двух или более символов подчёркивания и не заканчивается двумя или более такими символами, он считается приватным именем этого класса.
См. также
Точнее, перед генерацией кода приватные имена преобразуются в более длинную форму. Если преобразованное имя длиннее 255 символов, реализация может усечь его определённым образом.
Преобразование не зависит от синтаксического контекста, в котором используется идентификатор, но преобразуются только следующие приватные идентификаторы:
-
Любое имя, используемое в качестве имени переменной, которой присваивается значение или значение которой считывается, а также любое имя доступного атрибута.
Однако атрибут
__name__вложенных функций, классов и псевдонимов типов не преобразуется. - Имя импортируемого модуля, например
__spamвimport __spam. Если модуль входит в пакет (то есть его имя содержит точку), имя не преобразуется; например,__fooвimport __foo.barне преобразуется. - Имя импортируемого элемента, например
__fвfrom spam import __f.
Правило преобразования определяется следующим образом:
- Имя класса, из которого удалены начальные символы подчёркивания и добавлен один начальный символ подчёркивания, помещается перед идентификатором. Например, идентификатор
__spam, встречающийся в классе с именемFoo,_Fooили__Foo, преобразуется в_Foo__spam. - Если имя класса состоит только из символов подчёркивания, преобразование не выполняется. Например, идентификатор
__spam, встречающийся в классе с именем_или__, остаётся без изменений.
6.2.3. Литералы
Литерал — это текстовое представление значения. Python поддерживает числовые, строковые и байтовые литералы. Форматируемые строки и шаблонные строки рассматриваются как строковые литералы.
Числовые литералы состоят из одного токена NUMBER, обозначающего целое число, число с плавающей запятой или мнимое число. Подробности приведены в разделе Числовые литералы документации по лексическому анализу.
Строковые и байтовые литералы могут состоять из нескольких токенов. Подробности приведены в разделе Объединение строковых литералов.
Обратите внимание, что отрицательные и комплексные числа, например -3 или 3+4.2j, синтаксически не являются литералами, а представляют собой унарные или бинарные арифметические операции с оператором - или +.
Вычисление литерала даёт объект соответствующего типа (int, float, complex, str, bytes или Template) с заданным значением. В случае литералов с плавающей запятой и мнимых чисел значение может быть приближённым.
Формальная грамматика литералов:
literal: strings | NUMBER
6.2.3.1. Литералы и идентичность объектов
Все литералы соответствуют неизменяемым типам данных, поэтому идентичность объекта менее важна, чем его значение. При нескольких вычислениях литералов с одинаковым значением (как одного и того же вхождения в тексте программы, так и разных вхождений) может быть получен один и тот же объект или разные объекты с одинаковым значением.
Особенность реализации CPython
Например, в CPython небольшие целые числа с одинаковым значением при вычислении дают один и тот же объект:
>>> x = 7 >>> y = 7 >>> x is y True
Однако большие целые числа при вычислении дают разные объекты:
>>> x = 123456789 >>> y = 123456789 >>> x is y False
Это поведение может измениться в будущих версиях CPython. В частности, граница между «небольшими» и «большими» целыми числами уже менялась в прошлом.
CPython выдаст предупреждение SyntaxWarning, если сравнивать литералы с помощью is:
>>> x = 7 >>> x is 7 <input>:1: SyntaxWarning: "is" with 'int' literal. Did you mean "=="? True
Дополнительную информацию см. в разделе В каких случаях можно полагаться на проверку идентичности с помощью оператора is?.
Шаблонные строки неизменяемы, но могут ссылаться на изменяемые объекты в качестве значений Interpolation. Для целей этого раздела две t-строки имеют «одинаковое значение», если совпадают их структура и идентичность значений.
Особенность реализации CPython: В настоящее время при каждом вычислении шаблонной строки создаётся новый объект.
6.2.3.2. Объединение строковых литералов
Допускается записывать несколько соседних строковых или байтовых литералов, возможно, с разными способами заключения в кавычки. Их значение совпадает со значением их объединения:
>>> "hello" 'world' "helloworld"
Эта возможность определена на синтаксическом уровне и поэтому работает только с литералами. Для объединения строковых выражений во время выполнения можно использовать оператор «+»:
>>> greeting = "Hello" >>> space = " " >>> name = "Blaise" >>> print(greeting + space + name) # not: print(greeting space name) Hello Blaise
При объединении литералов можно свободно сочетать необрабатываемые строки, строки в тройных кавычках и форматируемые строковые литералы. Например:
>>> "Hello" r', ' f"{name}!"
"Hello, Blaise!"
Эту возможность можно использовать, чтобы уменьшить количество необходимых обратных косых черт, удобно разбить длинные строки на несколько строк кода или даже добавить комментарии к частям строк. Например:
re.compile("[A-Za-z_]" # letter or underscore
"[A-Za-z0-9_]*" # letter, digit or underscore
)
Однако байтовые литералы можно объединять только с другими байтовыми литералами, но не со строковыми литералами любого вида. Шаблонные строковые литералы также можно объединять только с другими шаблонными строковыми литералами:
>>> t"Hello" t"{name}!"
Template(strings=('Hello', '!'), interpolations=(...))
Формально:
strings: (STRING | fstring)+ | tstring+
6.2.4. Формы в скобках
Форма в скобках — это необязательный список выражений, заключённый в круглые скобки:
parenth_form: "(" [starred_expression] ")"
Выражение в скобках даёт то же, что и содержащийся в нём список выражений: если список содержит хотя бы одну запятую, он даёт кортеж; в противном случае он даёт единственное выражение, составляющее этот список.
Пустая пара круглых скобок даёт пустой объект-кортеж. Поскольку кортежи неизменяемы, к ним применяются те же правила, что и к литералам (то есть два вхождения пустого кортежа могут дать как один и тот же объект, так и разные объекты).
Обратите внимание, что кортежи образуются не круглыми скобками, а запятой. Исключением является пустой кортеж, для которого круглые скобки необходимы: разрешение на использование незаключённого в скобки «ничего» в выражениях привело бы к неоднозначностям и позволило бы не замечать распространённые опечатки.
6.2.5. Литералы списков, множеств и словарей
Для создания списка, множества или словаря в 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.6. Литералы списков
Литерал списка — это, возможно, пустая последовательность выражений, заключённая в квадратные скобки:
list_display: "[" [flexible_expression_list | comprehension] "]"
Литерал списка создаёт новый объект-список, содержимое которого задаётся списком выражений или генераторным выражением. Если задан список выражений, разделённых запятыми, они вычисляются слева направо и в том же порядке помещаются в объект-список. Если задано генераторное выражение, список создаётся из полученных в результате его вычисления элементов.
6.2.7. Литералы множеств
Литерал множества записывается в фигурных скобках и отличается от литерала словаря отсутствием двоеточий между ключами и значениями:
set_display: "{" (flexible_expression_list | comprehension) "}"
Литерал множества создаёт новый изменяемый объект-множество, содержимое которого задаётся последовательностью выражений или генераторным выражением. Если задан список выражений, разделённых запятыми, они вычисляются слева направо и добавляются в объект-множество. Если задано генераторное выражение, множество создаётся из полученных в результате его вычисления элементов.
Пустое множество нельзя создать с помощью {}; этот литерал создаёт пустой словарь.
6.2.8. Литералы словарей
Литерал словаря — это, возможно, пустая последовательность элементов словаря (пар ключ/значение), заключённая в фигурные скобки:
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.9. Генераторные выражения
Синтаксис генераторных выражений совпадает с синтаксисом генераторных выражений для списков, за исключением того, что они заключаются в круглые, а не квадратные скобки. Например:
>>> iterator = (x ** 2 for x in range(10)) >>> iterator <generator object <genexpr> at ...>
Во время выполнения генераторное выражение вычисляется в итератор-генератор, который выдаёт те же значения, что и соответствующее генераторное выражение для списка:
>>> list(iterator) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Таким образом, приведённый выше пример примерно эквивалентен определению и вызову следующей функции-генератора:
def make_generator_of_squares(iterator):
for x in iterator:
yield x ** 2
make_generator_of_squares(iter(range(10)))
Вызовы функций могут обходиться без внешних круглых скобок, если генераторное выражение является единственным позиционным аргументом и нет именованных аргументов. Подробности приведены в разделе Вызовы. Например:
# The parentheses after `sum` are part of the call syntax: >>> sum(x ** 2 for x in range(10)) 285 # The generator needs its own parentheses if it's not the only argument: >>> sum((x ** 2 for x in range(10)), start=1000) 1285
Итерируемое выражение в самой левой конструкции for вычисляется немедленно, поэтому ошибка, вызванная этим выражением, возникает в момент определения генераторного выражения, а не тогда, когда извлекается первое значение:
>>> (x ** 2 for x in nonexistent_iterable) Traceback (most recent call last): ... NameError: name 'nonexistent_iterable' is not defined
После вычисления выражения из его результата создаётся итератор так, как если бы к нему была применена функция iter(). Любая ошибка, возникающая при создании итератора, также возникает немедленно:
>>> (x ** 2 for x in None) Traceback (most recent call last): ... TypeError: 'NoneType' object is not iterable
Все остальные выражения вычисляются лениво, как и в обычных генераторах (то есть когда итератор запрашивают выдать значение):
>>> iterator = (nonexistent_value for x in range(10)) >>> iterator <generator object <genexpr> at ...> >>> list(iterator) Traceback (most recent call last): ... NameError: name 'nonexistent_value' is not defined
>>> iterator = (x * y for x in range(10) for y in nonexistent_iterable) >>> iterator <generator object <genexpr> at ...> >>> list(iterator) Traceback (most recent call last): ... NameError: name 'nonexistent_iterable' is not defined
Чтобы не нарушать ожидаемую работу самого генераторного выражения, выражения yield и yield from запрещены во вложенной неявной области видимости.
Если генераторное выражение содержит конструкции async for или выражения await, оно называется асинхронным генераторным выражением. Асинхронное генераторное выражение возвращает новый объект асинхронного генератора, являющийся асинхронным итератором (см. раздел Асинхронные итераторы).
Формальная грамматика генераторных выражений:
generator_expression: "(" expression comp_for ")"
Добавлено в версии 3.6: Добавлена поддержка асинхронных генераторных выражений.
Изменено в версии 3.7: До Python 3.7 асинхронные генераторные выражения могли использоваться только в корутинах async def. Начиная с версии 3.7, асинхронные генераторные выражения можно использовать в любой функции.
Изменено в версии 3.8: В неявно вложенной области видимости запрещены yield и yield from.
6.2.10. Выражения 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.10.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в точке, где функция-генератор была приостановлена (эквивалентно вызовуthrow(GeneratorExit)). Исключение возбуждается выражением yield, на котором генератор был приостановлен. Если функция-генератор перехватывает исключение и возвращает значение, это значение возвращается изclose(). Если функция-генератор уже закрыта или возбуждаетGeneratorExit(не перехватывая исключение),close()возвращаетNone. Если генератор выдаёт значение, возбуждается исключениеRuntimeError. Если генератор возбуждает любое другое исключение, оно передаётся вызывающему коду. Если генератор уже завершил работу из-за исключения или обычного завершения,close()возвращаетNoneи не оказывает другого эффекта.Изменено в версии 3.13: Если генератор возвращает значение при закрытии, это значение возвращается методом
close().
6.2.10.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.10.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.10.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 | call
6.3.1. Ссылки на атрибуты
Ссылка на атрибут — это первичное выражение, за которым следуют точка и имя:
attributeref: primary "." identifier
Первичное выражение должно вычисляться в объект типа, поддерживающего ссылки на атрибуты, как это делают большинство объектов. Затем этот объект запрашивают, чтобы получить атрибут с именем, заданным идентификатором. Тип и значение результата определяются объектом. При нескольких вычислениях одной и той же ссылки на атрибут могут получаться разные объекты.
Это поведение можно изменить, переопределив метод __getattribute__() или метод __getattr__(). Сначала вызывается метод __getattribute__(): он либо возвращает значение, либо возбуждает исключение AttributeError, если атрибут недоступен.
Если возбуждается исключение AttributeError и у объекта есть метод __getattr__(), этот метод вызывается в качестве запасного варианта.
6.3.2. Индексация и срезы
Синтаксис индексации обычно используется для выбора элемента из контейнера — например, для получения значения из dict:
>>> digits_by_name = {'one': 1, 'two': 2}
>>> digits_by_name['two'] # Subscripting a dictionary using the key 'two'
2
В синтаксисе индексации за объектом, к которому применяется индексация, — первичным выражением — следует индекс в квадратных скобках. В простейшем случае индекс представляет собой одно выражение.
В зависимости от типа объекта индекс иногда называют ключом (для отображений), индексом (для последовательностей) или аргументом типа (для обобщённых типов). С синтаксической точки зрения все эти варианты эквивалентны:
>>> colors = ['red', 'blue', 'green', 'black'] >>> colors[3] # Subscripting a list using the index 3 'black' >>> list[str] # Parameterizing the list type using the type argument str list[str]
Во время выполнения интерпретатор вычисляет первичное выражение и индекс, а затем вызывает специальный метод __getitem__() или __class_getitem__() первичного выражения, передавая индекс в качестве аргумента. Подробнее о том, какой из этих методов вызывается, см. в разделе __class_getitem__ и __getitem__.
Чтобы показать, как работает индексация, можно определить пользовательский объект, реализующий __getitem__() и выводящий значение индекса:
>>> class SubscriptionDemo:
... def __getitem__(self, key):
... print(f'subscripted with: {key!r}')
...
>>> demo = SubscriptionDemo()
>>> demo[1]
subscripted with: 1
>>> demo['a' * 3]
subscripted with: 'aaa'
О том, как встроенные типы обрабатывают индексацию, см. документацию __getitem__().
Индексация также может использоваться в качестве цели в операторах присваивания или удаления. В таких случаях интерпретатор вызывает специальный метод __setitem__() или __delitem__() индексируемого объекта соответственно, а не __getitem__().
>>> colors = ['red', 'blue', 'green', 'black'] >>> colors[3] = 'white' # Setting item at index >>> colors ['red', 'blue', 'green', 'white'] >>> del colors[3] # Deleting item at index 3 >>> colors ['red', 'blue', 'green']
Все расширенные формы индекса, описанные в следующих разделах, также можно использовать для присваивания и удаления.
6.3.2.1. Срезы
Более сложная форма индексации — срез — обычно используется для извлечения части последовательности. В этой форме индекс представляет собой срез: до трёх выражений, разделённых двоеточиями. Любое из выражений можно опустить, но срез должен содержать хотя бы одно двоеточие:
>>> number_names = ['zero', 'one', 'two', 'three', 'four', 'five'] >>> number_names[1:3] ['one', 'two'] >>> number_names[1:] ['one', 'two', 'three', 'four', 'five'] >>> number_names[:3] ['zero', 'one', 'two'] >>> number_names[:] ['zero', 'one', 'two', 'three', 'four', 'five'] >>> number_names[::2] ['zero', 'two', 'four'] >>> number_names[:-3] ['zero', 'one', 'two'] >>> del number_names[4:] >>> number_names ['zero', 'one', 'two', 'three']
При вычислении среза интерпретатор создаёт объект slice, атрибуты start, stop и step которого соответственно получают результаты вычисления выражений между двоеточиями. Результатом вычисления любого отсутствующего выражения будет None. Затем этот объект slice передаётся специальному методу __getitem__() или __class_getitem__(), как описано выше.
# continuing with the SubscriptionDemo instance defined above: >>> demo[2:3] subscripted with: slice(2, 3, None) >>> demo[::'spam'] subscripted with: slice(None, None, 'spam')
6.3.2.2. Индексы, разделённые запятыми
Индекс также можно задать в виде двух или более выражений либо срезов, разделённых запятыми:
# continuing with the SubscriptionDemo instance defined above: >>> demo[1, 2, 3] subscripted with: (1, 2, 3) >>> demo[1:2, 3] subscripted with: (slice(1, 2, None), 3)
Эта форма часто используется в числовых библиотеках для срезов многомерных данных. В этом случае интерпретатор создаёт tuple из результатов вычисления выражений или срезов и передаёт этот кортеж специальному методу __getitem__() или __class_getitem__(), как описано выше.
Индекс также можно задать в виде одного выражения или среза с последующей запятой, чтобы указать кортеж из одного элемента:
>>> demo['spam',]
subscripted with: ('spam',)
6.3.2.3. Индексы со звёздочкой
Добавлено в версии 3.11: Выражения в tuple_slices могут иметь звёздочку. См. PEP 646.
Индекс также может содержать выражение со звёздочкой. В этом случае интерпретатор распаковывает результат в кортеж и передаёт этот кортеж методу __getitem__() или __class_getitem__():
# continuing with the SubscriptionDemo instance defined above: >>> demo[*range(10)] subscripted with: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
Выражения со звёздочкой можно сочетать с выражениями и срезами, разделёнными запятыми:
>>> demo['a', 'b', *range(3), 'c']
subscripted with: ('a', 'b', 0, 1, 2, 'c')
6.3.2.4. Формальная грамматика индексации
subscription: primary '[' subscript ']' subscript: single_subscript | tuple_subscript single_subscript: proper_slice | assignment_expression proper_slice: [expression] ":" [expression] [ ":" [expression] ] tuple_subscript: ','.(single_subscript | starred_expression)+ [',']
Напомним, что оператор | обозначает упорядоченный выбор. В частности, в subscript, если подходят оба варианта, приоритет имеет первый (single_subscript).
6.3.3. Вызовы
Вызов вызывает вызываемый объект (например, функцию) с, возможно, пустой последовательностью аргументов:
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
Приостанавливает выполнение корутины на объекте ожидаемого типа. Может использоваться только внутри функции-корутины.
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__().
Изменено в версии 3.14: Если только один операнд является комплексным числом, другой операнд преобразуется в число с плавающей точкой.
Оператор @ (собачка) предназначен для умножения матриц. Ни один из встроенных типов 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__().
Изменено в версии 3.14: Если только один операнд является комплексным числом, другой операнд преобразуется в число с плавающей точкой.
Оператор - (вычитание) возвращает разность аргументов. Сначала числовые аргументы приводятся к общему вещественному типу.
Это поведение можно изменить с помощью специальных методов __sub__() и __rsub__().
Изменено в версии 3.14: Если только один операнд является комплексным числом, другой операнд преобразуется в число с плавающей точкой.
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__() или __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 == xx != yиy != xx < yиy > xx <= yиy >= x -
Сравнение должно быть транзитивным. Следующие (не исчерпывающие) примеры это иллюстрируют:
x > y and y > zподразумеваетx > zx < y and y <= zподразумеваетx < z -
Обратное сравнение должно давать логическое отрицание. Иными словами, следующие выражения должны давать одинаковый результат:
x == yиnot x != yx < yиnot x >= y(для полного порядка)x > yиnot x <= y(для полного порядка)Два последних выражения применимы к коллекциям с полным порядком (например, к последовательностям, но не к множествам и отображениям). См. также декоратор
@~functools.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
Условное выражение (иногда называемое «тернарным оператором») является альтернативой оператору if-else. Поскольку это выражение, оно возвращает значение и может использоваться как подвыражение.
Выражение 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 | expression 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 — от самого высокого (наиболее сильное связывание) до самого низкого (наименее сильное связывание). Операторы в одной строке имеют одинаковый приоритет. Если синтаксис не указан явно, операторы являются бинарными. Операторы в одной строке группируются слева направо (за исключением возведения в степень и условных выражений, которые группируются справа налево).
Обратите внимание, что сравнения, проверки на вхождение и проверки идентичности имеют одинаковый приоритет и поддерживают последовательное применение слева направо, как описано в разделе Сравнения.
Оператор | Описание |
|---|---|
|
| Связывание или выражение в скобках, отображение списка, словаря или множества |
| Индексация (включая срезы), вызов, ссылка на атрибут |
Выражение ожидания | |
| Возведение в степень [5] |
| Унарный плюс, унарный минус, побитовое НЕ |
| Умножение, матричное умножение, деление, целочисленное деление, остаток [6] |
| Сложение и вычитание |
| Сдвиги |
| Побитовое И |
| Побитовое исключающее ИЛИ |
| Побитовое ИЛИ |
Сравнения, включая проверки на вхождение и проверки идентичности | |
Логическое НЕ | |
Логическое И | |
Логическое ИЛИ | |
| Условное выражение |
Лямбда-выражение | |
| Выражение присваивания |
Сноски
© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/reference/expressions.html