Spec-Zone.ru › Python 3.13

Составные операторы

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

Операторы if, while и for реализуют традиционные конструкции управления потоком. try указывает обработчики исключений и/или код очистки для группы операторов, а оператор with позволяет выполнять код инициализации и завершения вокруг блока кода. Определения функций и классов также являются составными операторами с точки зрения синтаксиса.

Составной оператор состоит из одного или нескольких «клаузул». Клаузула состоит из заголовка и «блока». Заголовки клаузул конкретного составного оператора находятся на одном уровне отступа. Каждый заголовок клаузулы начинается с уникального ключевого слова и заканчивается двоеточием. Блок — это группа операторов, управляемых клаузулой. Блок может представлять собой один или несколько операторов, разделённых точкой с запятой, в той же строке, что и заголовок, после двоеточия, или один или несколько отступленных операторов в последующих строках. Только последний вид блока может содержать вложенные составные операторы; следующее является незаконным, в основном потому, что не ясно, к какой клаузе if будет принадлежать последующая клауза else:

if test1: if test2: print(x)

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

if x < y < z: print(x); print(y); print(z)

Резюмируя:

compound_stmt ::=  if_stmt
                   | while_stmt
                   | for_stmt
                   | try_stmt
                   | with_stmt
                   | match_stmt
                   | funcdef
                   | classdef
                   | async_with_stmt
                   | async_for_stmt
                   | async_funcdef
suite         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement     ::=  stmt_list NEWLINE | compound_stmt
stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]

Обратите внимание, что операторы всегда заканчиваются NEWLINE и возможно, за ним следует DEDENT. Также обратите внимание, что необязательные клаузы продолжения всегда начинаются с ключевого слова, которым нельзя начать оператор, таким образом, нет неоднозначностей (проблема «висящего else» решена в Python требованием, чтобы вложенные операторы if были отступлены).

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

8.1. Оператор if

Оператор if используется для условного выполнения:

if_stmt ::=  "if" assignment_expression ":" suite
             ("elif" assignment_expression ":" suite)*
             ["else" ":" suite]

Он выбирает ровно один из блоков, оценивая выражения одно за другим, пока не будет найдено истинное выражение (см. раздел Булевы операции для определения истинности и ложности); затем этот блок выполняется (и никакая другая часть оператора if не выполняется или оценивается). Если все выражения ложны, выполняется блок клаузы else, если она есть.

8.2. Оператор while

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

while_stmt ::=  "while" assignment_expression ":" suite
                ["else" ":" suite]

Это многократно проверяет выражение и, если оно истинно, выполняет первый блок; если выражение ложно (что может быть в первый раз, когда оно проверяется), выполняется блок клаузы else , если она присутствует, и цикл завершается.

Оператор break, выполняемый в первом блоке, завершает цикл, не выполняя блок клаузы else. Оператор continue, выполняемый в первом блоке, пропускает остальную часть блока и возвращается к проверке выражения.

8.3. Оператор for

Оператор for используется для итерации по элементам последовательности (например, строки, кортежа или списка) или другого итерируемого объекта:

for_stmt ::=  "for" target_list "in" starred_list ":" suite
              ["else" ":" suite]

Выражение starred_list вычисляется один раз; оно должно возвращать итерируемый объект. Для этого итерируемого объекта создается итератор. Первый элемент, предоставленный итератором, присваивается списку целевых переменных по стандартным правилам присваивания (см. Операторы присваивания), и выполняется блок. Это повторяется для каждого элемента, предоставляемого итератором. Когда итератор исчерпан, выполняется блок клаузы else , если она присутствует, и цикл завершается.

Оператор break, выполняемый в первом блоке, завершает цикл, не выполняя блок клаузы else. Оператор continue, выполняемый в первом блоке, пропускает остальную часть блока и переходит к следующему элементу или к клаузе else , если следующего элемента нет.

Цикл for выполняет присваивание переменным в списке целей. Это перезаписывает все предыдущие присваивания этим переменным, включая те, которые сделаны в блоке цикла for:

for i in range(10):
    print(i)
    i = 5             # this will not affect the for-loop
                      # because i will be overwritten with the next
                      # index in the range

Имена в списке целей не удаляются по окончании цикла, но если последовательность пустая, им не будет присвоено значение циклом. Подсказка: встроенный тип range() представляет собой неизменяемые арифметические последовательности целых чисел. Например, итерация range(3) последовательно возвращает 0, 1 и затем 2.

Изменено в версии 3.11: Звездочные элементы теперь разрешены в списке выражений.

8.4. Оператор try

Оператор try задаёт обработчики исключений и/или код очистки для группы операторов:

try_stmt  ::=  try1_stmt | try2_stmt | try3_stmt
try1_stmt ::=  "try" ":" suite
               ("except" [expression ["as" identifier]] ":" suite)+
               ["else" ":" suite]
               ["finally" ":" suite]
try2_stmt ::=  "try" ":" suite
               ("except" "*" expression ["as" identifier] ":" suite)+
               ["else" ":" suite]
               ["finally" ":" suite]
try3_stmt ::=  "try" ":" suite
               "finally" ":" suite

Дополнительную информацию об исключениях можно найти в разделе Исключения, а информацию об использовании оператора raise для генерации исключений — в разделе Оператор raise.

8.4.1. Блок except

Блок(и) except задают один или несколько обработчиков исключений. Если в блоке try исключение не возникает, никакой обработчик не выполняется. Если исключение возникает в блоке try , начинается поиск обработчика исключений. Поиск происходит поочерёдно по блокам except , пока не будет найден совпадающий с исключением. Если присутствует блок except без выражения, то он должен быть последним и обрабатывает любое исключение.

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

Если ни один блок except не соответствует исключению, поиск обработчика исключений продолжается в окружающем коде и на стеке вызовов. [1]

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

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

Когда исключение было присвоено с помощью as target, оно очищается в конце блока except . Это так, как будто

except E as N:
    foo

было переведено в

except E as N:
    try:
        foo
    finally:
        del N

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

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

>>> print(sys.exception())
None
>>> try:
...     raise TypeError
... except:
...     print(repr(sys.exception()))
...     try:
...          raise ValueError
...     except:
...         print(repr(sys.exception()))
...     print(repr(sys.exception()))
...
TypeError()
ValueError()
TypeError()
>>> print(sys.exception())
None

8.4.2. Блок except*

Блок(и) except* используются для обработки ExceptionGroupов. Тип исключения для сопоставления интерпретируется так же, как и в случае с блоком except, но в случае групп исключений у нас могут быть частичные совпадения, когда тип соответствует некоторым исключениям в группе. Это означает, что могут быть выполнены несколько блоков except* , каждый из которых обрабатывает часть группы исключений. Каждый блок выполняется не более одного раза и обрабатывает группу исключений всех соответствующих исключений. Каждое исключение в группе обрабатывается не более чем одним блоком except* , первым, которому оно соответствует.

>>> try:
...     raise ExceptionGroup("eg",
...         [ValueError(1), TypeError(2), OSError(3), OSError(4)])
... except* TypeError as e:
...     print(f'caught {type(e)} with nested {e.exceptions}')
... except* OSError as e:
...     print(f'caught {type(e)} with nested {e.exceptions}')
...
caught <class 'ExceptionGroup'> with nested (TypeError(2),)
caught <class 'ExceptionGroup'> with nested (OSError(3), OSError(4))
  + Exception Group Traceback (most recent call last):
  |   File "<stdin>", line 2, in <module>
  | ExceptionGroup: eg
  +-+---------------- 1 ----------------
    | ValueError: 1
    +------------------------------------

Любые оставшиеся исключения, которые не были обработаны ни одним блоком except* , повторно поднимаются в конце, вместе со всеми исключениями, которые были подняты изнутри блоков except* . Если этот список содержит более одного исключения для повторного поднятия, они объединяются в группу исключений.

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

>>> try:
...     raise BlockingIOError
... except* BlockingIOError as e:
...     print(repr(e))
...
ExceptionGroup('', (BlockingIOError()))

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

Невозможно смешивать блоки except и блоки except* в одном блоке try. break, continue и return не могут появляться в блоке except*.

8.4.3. Блок else

Необязательный блок else выполняется, если поток управления выходит из блока try, исключение не было поднято, и не был выполнен оператор return, continue или break. Исключения в блоке else не обрабатываются предшествующими блоками except.

8.4.4. Блок finally

Если блок finally присутствует, он определяет обработчик «очистки». Блок try выполняется, включая любые блоки except и else. Если в одном из блоков возникает исключение, которое не обрабатывается, исключение временно сохраняется. Выполняется блок finally . Если сохранено исключение, оно повторно поднимается в конце блока finally . Если блок finally вызывает другое исключение, сохранённое исключение устанавливается как контекст нового исключения. Если блок finally выполняет оператор return, break или continue, сохранённое исключение отбрасывается:

>>> def f():
...     try:
...         1/0
...     finally:
...         return 42
...
>>> f()
42

Информация об исключении недоступна программе во время выполнения блока finally.

Когда в блоке try оператора try…finally выполняется оператор return, break или continue, блок finally также выполняется «на выходе».

Значение возврата функции определяется последним оператором return, который выполняется. Поскольку блок finally всегда выполняется, оператор return , выполненный в блоке finally , всегда будет последним выполненным:

>>> def foo():
...     try:
...         return 'try'
...     finally:
...         return 'finally'
...
>>> foo()
'finally'

Изменено в версии 3.8: До Python 3.8 оператор continue был недопустим в блоке finally из-за проблемы с реализацией.

8.5. Оператор with

Оператор with используется для обертывания выполнения блока методами, определёнными управляющей контекстом (см. раздел Управляющие контекстом с помощью оператора With). Это позволяет encapsulate общие шаблоны try…except…finally для удобного повторного использования.

with_stmt          ::=  "with" ( "(" with_stmt_contents ","? ")" | with_stmt_contents ) ":" suite
with_stmt_contents ::=  with_item ("," with_item)*
with_item          ::=  expression ["as" target]

Выполнение оператора with с одним «элементом» происходит следующим образом:

  1. Выражение контекста (выражение, заданное в with_item) вычисляется для получения управляющей контекстом.
  2. Загружается метод __enter__() управляющей контекстом для последующего использования.
  3. Загружается метод __exit__() управляющей контекстом для последующего использования.
  4. Вызывается метод __enter__() управляющей контекстом.
  5. Если в операторе with был указан целевой объект, то возвращаемое значение метода __enter__() присваивается ему.

    Примечание

    Оператор with гарантирует, что если метод __enter__() возвращает результат без ошибки, то метод __exit__() всегда будет вызван. Таким образом, если ошибка произойдёт во время присваивания значений целевым переменным, она будет обработана так же, как если бы ошибка возникла внутри блока.

  6. Выполняется блок кода.
  7. Вызывается метод __exit__() управляющей контекстом. Если выполнение блока кода завершилось с исключением, тип, значение и отслеживание исключения передаются методу __exit__() в качестве аргументов. В противном случае передаются три аргумента None.

    Если выполнение блока кода завершилось с исключением, и возвращаемое значение метода __exit__() было ложным, исключение перевыводится. Если возвращаемое значение было истинным, исключение подавляется, и выполнение продолжается со следующей за оператором with инструкцией.

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

Следующий код:

with EXPRESSION as TARGET:
    SUITE

семантически эквивалентен:

manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)

try:
    TARGET = value
    SUITE
except:
    if not exit(manager, *sys.exc_info()):
        raise
else:
    exit(manager, None, None, None)

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

with A() as a, B() as b:
    SUITE

семантически эквивалентно:

with A() as a:
    with B() as b:
        SUITE

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

with (
    A() as a,
    B() as b,
):
    SUITE

Изменено в версии 3.1: Поддержка нескольких выражений контекста.

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

См. также

PEP 343 - Оператор «with»

Спецификация, предыстория и примеры оператора Python with.

8.6. Оператор match

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

Оператор match используется для сопоставления с образцом. Синтаксис:

match_stmt   ::=  'match' subject_expr ":" NEWLINE INDENT case_block+ DEDENT
subject_expr ::=  star_named_expression "," star_named_expressions?
                  | named_expression
case_block   ::=  'case' patterns [guard] ":" block

Примечание

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

Сопоставление с образцом принимает шаблон в качестве входных данных (после case) и значение объекта (после match). Шаблон (который может содержать подшаблоны) сопоставляется со значением объекта. Результатами являются:

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

Ключевые слова match и case являются мягкими ключевыми словами.

См. также

  • PEP 634 – Спецификация структурного сопоставления с образцом
  • PEP 636 – Руководство по структурному сопоставлению с образцом

8.6.1. Обзор

Ниже представлен обзор логической последовательности оператора match:

  1. Вычисляется выражение объекта subject_expr и получается соответствующее значение объекта. Если выражение объекта содержит запятую, создается кортеж в соответствии со стандартными правилами.
  2. Каждый шаблон в case_block пытается сопоставиться со значением объекта. Конкретные правила для успеха или неудачи описаны ниже. Попытка сопоставления также может связать некоторые или все отдельные имена в шаблоне. Точные правила привязки шаблонов зависят от типа шаблона и указаны ниже. Привязки имен, сделанные во время успешного сопоставления с шаблоном, сохраняются после блока и могут быть использованы после оператора match.

    Примечание

    При неудачном сопоставлении с образцом некоторые подшаблоны могут быть успешны. Не полагайтесь на то, что привязки будут выполнены при неудачном сопоставлении. И наоборот, не полагайтесь на то, что переменные останутся неизменными после неудачного сопоставления. Точное поведение зависит от реализации и может меняться. Это преднамеренное решение, позволяющее различным реализациям добавлять оптимизации.

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

    • Если условие вычисляется как true или отсутствует, выполняется block внутри case_block.
    • В противном случае, как описано выше, делается попытка сопоставить следующий case_block.
    • Если нет дальнейших блоков case, выполнение оператора match завершается.

Примечание

Пользователи, как правило, не должны полагаться на то, что шаблон будет вычислен. В зависимости от реализации интерпретатор может кэшировать значения или использовать другие оптимизации, которые пропускают повторные вычисления.

Пример оператора match:

>>> flag = False
>>> match (100, 200):
...    case (100, 300):  # Mismatch: 200 != 300
...        print('Case 1')
...    case (100, 200) if flag:  # Successful match, but guard fails
...        print('Case 2')
...    case (100, y):  # Matches and binds y to 200
...        print(f'Case 3, y: {y}')
...    case _:  # Pattern not attempted
...        print('Case 4, I match anything!')
...
Case 3, y: 200

В этом случае, if flag является условием. Подробнее об этом в следующем разделе.

8.6.2. Условие

guard ::=  "if" named_expression

Условие guard (которое является частью case) должно быть выполнено для выполнения кода внутри блока case. Оно имеет вид: if за которым следует выражение.

Логическая последовательность блока case с guard:

  1. Проверьте, был ли успешно выполнен шаблон в блоке case . Если шаблон не совпал, guard не вычисляется, и проверяется следующий блок case.
  2. Если шаблон совпал, вычислите guard.

    • Если условие guard вычисляется как true, блок case выбирается.
    • Если условие guard вычисляется как false, блок case не выбирается.
    • Если условие guard вызывает исключение во время вычисления, исключение поднимается вверх.

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

8.6.3. Неопровержимые блоки case

Блок case считается неопровержимым, если в нем нет условия и шаблон неопровержим. Оператор match может иметь не более одного неопровержимого блока case, и он должен быть последним.

Блок case считается неопровержимым, если у него нет условия и шаблон неопровержим. Шаблон считается неопровержимым, если по его синтаксису можно однозначно определить, что он всегда будет успешным. Только следующие шаблоны являются неопровержимыми:

  • Шаблоны AS у которых левая часть неопровержима
  • Шаблоны OR содержащие по крайней мере один неопровержимый шаблон
  • Шаблоны capture
  • Шаблоны wildcard
  • скобочные неопровержимые шаблоны

8.6.4. Шаблоны

Примечание

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

  • обозначение SEP.RULE+ является сокращением для RULE (SEP RULE)*
  • обозначение !RULE является сокращением для утверждения отрицательного предвосхищения

Синтаксис верхнего уровня для patterns:

patterns       ::=  open_sequence_pattern | pattern
pattern        ::=  as_pattern | or_pattern
closed_pattern ::=  | literal_pattern
                    | capture_pattern
                    | wildcard_pattern
                    | value_pattern
                    | group_pattern
                    | sequence_pattern
                    | mapping_pattern
                    | class_pattern

В следующих описаниях будет включено описание «простыми словами» того, что делает шаблон для целей иллюстрации (благодаря Раймону Хеттингера за документ, который вдохновил большинство описаний). Обратите внимание, что эти описания предназначены только для целей иллюстрации и могут не отражать реализацию в основе. Кроме того, они не охватывают все допустимые формы.

8.6.4.1. Шаблоны ИЛИ

Шаблон ИЛИ — это два или более шаблонов, разделенных вертикальными чертами |. Синтаксис:

or_pattern ::=  "|".closed_pattern+

Только последний подшаблон может быть непреложным, и каждый подшаблон должен связывать тот же набор имен, чтобы избежать неоднозначности.

Шаблон ИЛИ последовательно сопоставляет каждый из своих подшаблонов со значением объекта, пока один не увенчается успехом. Затем шаблон ИЛИ считается успешным. В противном случае, если ни один из подшаблонов не увенчается успехом, шаблон ИЛИ терпит неудачу.

Простыми словами, P1 | P2 | ... будет пытаться сопоставить P1, если это не удастся, он будет пытаться сопоставить P2, сразу увенчавшись успехом, если это произойдет, в противном случае потерпит неудачу.

8.6.4.2. Шаблоны КАК

Шаблон КАК сопоставляет шаблон ИЛИ слева от ключевого слова as с объектом. Синтаксис:

as_pattern ::=  or_pattern "as" capture_pattern

Если шаблон ИЛИ терпит неудачу, шаблон КАК терпит неудачу. В противном случае шаблон КАК связывает объект с именем справа от ключевого слова as и увенчивается успехом. capture_pattern не может быть _.

Простыми словами P as NAME будет соответствовать P, и при успехе он установит NAME = <subject>.

8.6.4.3. Литеральные шаблоны

Литеральный шаблон соответствует большинству литералов в Python. Синтаксис:

literal_pattern ::=  signed_number
                     | signed_number "+" NUMBER
                     | signed_number "-" NUMBER
                     | strings
                     | "None"
                     | "True"
                     | "False"
signed_number   ::=  ["-"] NUMBER

Правило strings и токен NUMBER определены в стандартной грамматике Python. Поддерживаются строковые литералы с тройными кавычками. Поддерживаются сырые строки и байтовые строки. f-строки не поддерживаются.

Формы signed_number '+' NUMBER и signed_number '-' NUMBER предназначены для выражения комплексных чисел; они требуют вещественного числа слева и мнимого числа справа. Например, 3 + 4j.

Простыми словами, LITERAL будет успешным только если <subject> == LITERAL. Для синглтонов None, True и False используется оператор is.

8.6.4.4. Шаблоны захвата

Шаблон захвата связывает значение объекта с именем. Синтаксис:

capture_pattern ::=  !'_' NAME

Одиночный символ подчеркивания _ не является шаблоном захвата (это то, что выражает !'_'). Вместо этого он обрабатывается как wildcard_pattern.

В данном шаблоне данное имя может быть связано только один раз. Например, case x, x: ... недопустимо, тогда как case [x] | x: ... разрешено.

Шаблоны захвата всегда успешны. Связывание следует правилам области видимости, установленным оператором выражения присваивания в PEP 572; имя становится локальной переменной в ближайшей содержащей функции области видимости, если нет применимого global или nonlocal оператора.

Простыми словами, NAME всегда будет успешным и установит NAME = <subject>.

8.6.4.5. Шаблоны подстановки

Шаблон подстановки всегда успешен (сопоставляется с чем угодно) и не связывает никаких имен. Синтаксис:

wildcard_pattern ::=  '_'

_ является мягким ключевым словом внутри любого шаблона, но только внутри шаблонов. Это идентификатор, как обычно, даже внутри match выражений объекта, guard и case блоков.

Простыми словами, _ всегда будет успешным.

8.6.4.6. Шаблоны значений

Шаблон значения представляет собой именованное значение в Python. Синтаксис:

value_pattern ::=  attr
attr          ::=  name_or_attr "." NAME
name_or_attr  ::=  attr | NAME

Точечное имя в шаблоне ищется с использованием стандартных Python правил разрешения имен. Шаблон успешен, если найденное значение сравнивается как равное значению объекта (используя оператор равенства ==).

Простыми словами, NAME1.NAME2 будет успешным только если <subject> == NAME1.NAME2

Примечание

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

8.6.4.7. Шаблоны групп

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

group_pattern ::=  "(" pattern ")"

Простыми словами (P) имеет тот же эффект, что и P.

8.6.4.8. Шаблоны последовательностей

Шаблон последовательности содержит несколько подшаблонов, которые должны быть сопоставлены с элементами последовательности. Синтаксис аналогичен распаковке списка или кортежа.

sequence_pattern       ::=  "[" [maybe_sequence_pattern] "]"
                            | "(" [open_sequence_pattern] ")"
open_sequence_pattern  ::=  maybe_star_pattern "," [maybe_sequence_pattern]
maybe_sequence_pattern ::=  ",".maybe_star_pattern+ ","?
maybe_star_pattern     ::=  star_pattern | pattern
star_pattern           ::=  "*" (capture_pattern | wildcard_pattern)

Разницы нет, если используются круглые или квадратные скобки для шаблонов последовательностей (т.е. (...) против [...] ).

Примечание

Один шаблон в круглых скобках без заключительной запятой (например, (3 | 4)) является шаблоном группы. В то время как один шаблон в квадратных скобках (например, [3 | 4]) по-прежнему является шаблоном последовательности.

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

Следующий является логическим потоком для сопоставления шаблона последовательности со значением объекта:

  1. Если значение объекта не является последовательностью [2], шаблон последовательности терпит неудачу.
  2. Если значение объекта является экземпляром str, bytes или bytearray, шаблон последовательности терпит неудачу.
  3. Следующие шаги зависят от того, является ли шаблон последовательности фиксированной или переменной длины.

    Если шаблон последовательности имеет фиксированную длину:

    1. Если длина последовательности объекта не равна количеству подшаблонов, шаблон последовательности терпит неудачу
    2. Подшаблоны в шаблоне последовательности сопоставляются с соответствующими элементами в последовательности объекта слева направо. Сопоставление прекращается, как только один из подшаблонов потерпит неудачу. Если все подшаблоны успешно сопоставят свои соответствующие элементы, шаблон последовательности будет успешным.

    В противном случае, если шаблон последовательности имеет переменную длину:

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

    Примечание

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

Простыми словами, [P1, P2, P3, … , P<N>] совпадает только если происходит следующее:

  • проверка <subject> — это последовательность
  • len(subject) == <N>
  • P1 сопоставляется с <subject>[0] (обратите внимание, что это сопоставление также может связывать имена)
  • P2 сопоставляется с <subject>[0] (обратите внимание, что это сопоставление также может связывать имена)
  • … и так далее для соответствующего шаблона/элемента.

8.6.4.9. Шаблоны отображения

Шаблон отображения содержит один или несколько шаблонов ключ-значение. Синтаксис похож на построение словаря. Синтаксис:

mapping_pattern     ::=  "{" [items_pattern] "}"
items_pattern       ::=  ",".key_value_pattern+ ","?
key_value_pattern   ::=  (literal_pattern | value_pattern) ":" pattern
                         | double_star_pattern
double_star_pattern ::=  "**" capture_pattern

В шаблоне отображения может быть не более одного шаблона с двойной звездочкой. Шаблон с двойной звездочкой должен быть последним подшаблоном в шаблоне отображения.

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

Следующее представляет собой логический поток сопоставления шаблона отображения со значением объекта:

  1. Если значение объекта не является отображением [3], шаблон отображения не соответствует.
  2. Если все ключи, заданные в шаблоне отображения, присутствуют в отображении объекта, и шаблон для каждого ключа соответствует соответствующему элементу отображения объекта, шаблон отображения соответствует.
  3. Если обнаружены дублирующие ключи в шаблоне отображения, шаблон считается недействительным. SyntaxError генерируется для дублирующих литеральных значений; или ValueError для именованных ключей с одинаковым значением.

Примечание

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

Проще говоря, {KEY1: P1, KEY2: P2, ... } соответствует только в том случае, если выполняется всё из следующего:

  • проверка <subject> является отображением
  • KEY1 in <subject>
  • P1 соответствует <subject>[KEY1]
  • … и так далее для соответствующей пары КЛЮЧ/шаблон.

8.6.4.10. Шаблоны классов

Шаблон класса представляет собой класс и его позиционные и ключевые аргументы (если таковые имеются). Синтаксис:

class_pattern       ::=  name_or_attr "(" [pattern_arguments ","?] ")"
pattern_arguments   ::=  positional_patterns ["," keyword_patterns]
                         | keyword_patterns
positional_patterns ::=  ",".pattern+
keyword_patterns    ::=  ",".keyword_pattern+
keyword_pattern     ::=  NAME "=" pattern

Один и тот же ключевой аргумент не должен повторяться в шаблонах классов.

Следующий логический поток сопоставления шаблона класса со значением объекта:

  1. Если name_or_attr не является экземпляром встроенного type, генерируется TypeError.
  2. Если значение объекта не является экземпляром name_or_attr (проверяется с помощью isinstance()), шаблон класса не соответствует.
  3. Если аргументы шаблона отсутствуют, шаблон соответствует. В противном случае, последующие шаги зависят от наличия шаблонов ключевых или позиционных аргументов.

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

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

    I. Ключ ищется в качестве атрибута объекта.

    • Если это вызывает исключение, отличное от AttributeError, исключение передается выше.
    • Если это вызывает AttributeError, шаблон класса не соответствует.
    • В противном случае, подшаблон, связанный с ключевым шаблоном, сопоставляется со значением атрибута объекта. Если это не соответствует, шаблон класса не соответствует; если это соответствует, соответствие переходит к следующему ключевому.

    II. Если все ключевые шаблоны соответствуют, шаблон класса соответствует.

    Если присутствуют позиционные шаблоны, они преобразуются в ключевые шаблоны с использованием атрибута __match_args__ класса name_or_attr перед сопоставлением:

    I. Вызывается эквивалент getattr(cls, "__match_args__", ()).

    • Если это вызывает исключение, исключение передается выше.
    • Если возвращаемое значение не является кортежем, преобразование не выполняется и генерируется TypeError.
    • Если позиционных шаблонов больше, чем len(cls.__match_args__), генерируется TypeError.
    • В противном случае, позиционный шаблон i преобразуется в ключевой шаблон, используя __match_args__[i] в качестве ключевого слова. __match_args__[i] должен быть строкой; в противном случае генерируется TypeError.
    • Если имеются дублирующие ключевые слова, генерируется TypeError.

    См. также

    Настройка позиционных аргументов в сопоставлении с шаблоном класса

    II. После преобразования всех позиционных шаблонов в ключевые

    сопоставление продолжается так, как если бы были только ключевые шаблоны.

    Для следующих встроенных типов обработка позиционных подшаблонов отличается:

    • bool
    • bytearray
    • bytes
    • dict
    • float
    • frozenset
    • int
    • list
    • set
    • str
    • tuple

    Эти классы принимают один позиционный аргумент, и шаблон в этом случае сопоставляется со всем объектом, а не с атрибутом. Например, int(0|1) соответствует значению 0, но не значению 0.0.

Проще говоря, CLS(P1, attr=P2) соответствует только в том случае, если выполняется всё из следующего:

  • isinstance(<subject>, CLS)
  • преобразование P1 в ключевой шаблон с помощью CLS.__match_args__
  • Для каждого ключевого аргумента attr=P2,

    • hasattr(<subject>, "attr")
    • P2 соответствует <subject>.attr
  • … и так далее для соответствующей пары ключевого аргумента/шаблона.

См. также

  • PEP 634 – Структурное сопоставление с образцом: Спецификация
  • PEP 636 – Структурное сопоставление с образцом: Руководство

8.7. Определения функций

Определение функции задаёт объект пользовательской функции (см. раздел Иерархия стандартных типов):

funcdef                   ::=  [decorators] "def" funcname [type_params] "(" [parameter_list] ")"
                               ["->" expression] ":" suite
decorators                ::=  decorator+
decorator                 ::=  "@" assignment_expression NEWLINE
parameter_list            ::=  defparameter ("," defparameter)* "," "/" ["," [parameter_list_no_posonly]]
                                 | parameter_list_no_posonly
parameter_list_no_posonly ::=  defparameter ("," defparameter)* ["," [parameter_list_starargs]]
                               | parameter_list_starargs
parameter_list_starargs   ::=  "*" [star_parameter] ("," defparameter)* ["," ["**" parameter [","]]]
                               | "**" parameter [","]
parameter                 ::=  identifier [":" expression]
star_parameter            ::=  identifier [":" ["*"] expression]
defparameter              ::=  parameter ["=" expression]
funcname                  ::=  identifier

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

Определение функции не выполняет тело функции; оно выполняется только при вызове функции. [4]

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

@f1(arg)
@f2
def func(): pass

приблизительно эквивалентен

def func(): pass
func = f1(arg)(f2(func))

за исключением того, что исходная функция временно не связывается с именем func.

Изменено в версии 3.9: Функции могут быть декорированы любым допустимым выражением assignment_expression. Ранее грамматика была значительно более ограниченной; см. PEP 614 для получения подробностей.

Список параметров типа может быть указан в квадратных скобках между именем функции и открывающей скобкой списка её параметров. Это указывает статическим анализаторам типов, что функция является универсальной. Во время выполнения параметры типа могут быть получены из атрибута функции __type_params__. Дополнительные сведения см. в разделе Универсальные функции.

Изменено в версии 3.12: Списки параметров типа являются новыми в Python 3.12.

Когда один или несколько параметров имеют вид параметр = выражение, функция считается имеющей «значения параметров по умолчанию». Для параметра с значением по умолчанию соответствующий аргумент может быть опущен из вызова, в этом случае для параметра подставляется его значение по умолчанию. Если параметр имеет значение по умолчанию, все последующие параметры вплоть до «*» также должны иметь значение по умолчанию — это синтаксическое ограничение, которое не выражено в грамматике.

Значения параметров по умолчанию вычисляются слева направо при выполнении определения функции. Это означает, что выражение вычисляется один раз при определении функции, и то же «предварительно вычисленное» значение используется для каждого вызова. Это особенно важно понимать, когда значение параметра по умолчанию является изменяемым объектом, например, списком или словарем: если функция изменяет объект (например, добавляет элемент в список), значение параметра по умолчанию фактически изменяется. Это обычно не то, что предполагалось. Способ обойти это — использовать None в качестве значения по умолчанию и явно проверить его в теле функции, например:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

Семантика вызова функции более подробно описана в разделе Вызовы. Вызов функции всегда присваивает значения всем параметрам, указанным в списке параметров, либо из позиционных аргументов, из именованных аргументов, либо из значений по умолчанию. Если присутствует форма «*identifier», она инициализируется кортежем, получающим любые дополнительные позиционные параметры, по умолчанию — пустым кортежем. Если присутствует форма «**identifier», она инициализируется новым упорядоченным отображением, получающим любые дополнительные именованные аргументы, по умолчанию — новым пустым отображением того же типа. Параметры после «*» или «*identifier» являются именованными параметрами и могут передаваться только через именованные аргументы. Параметры до «/» являются позиционными параметрами и могут передаваться только через позиционные аргументы.

Изменено в версии 3.8: Синтаксис параметра функции / может использоваться для обозначения позиционных-только параметров. См. PEP 570 для получения подробностей.

Параметры могут иметь аннотацию в форме «: expression» после имени параметра. Любой параметр может иметь аннотацию, даже те, что имеют вид *identifier или **identifier. (В качестве специального случая, параметры вида *identifier могут иметь аннотацию «: *expression».) Функции могут иметь аннотацию «возвращаемого значения» в форме «-> expression» после списка параметров. Эти аннотации могут быть любыми допустимыми выражениями Python. Наличие аннотаций не изменяет семантики функции. Значения аннотаций доступны в качестве значений словаря, ключами которого являются имена параметров, в атрибуте __annotations__ объекта функции. Если используется импорт annotations из __future__, аннотации сохраняются как строки во время выполнения, что позволяет отложить вычисление. В противном случае они вычисляются при выполнении определения функции. В этом случае аннотации могут быть вычислены в другом порядке, чем они появляются в исходном коде.

Изменено в версии 3.11: Параметры вида «*identifier» могут иметь аннотацию «: *expression». См. PEP 646.

Также возможно создание анонимных функций (функций, не связанных с именем), для немедленного использования в выражениях. Для этого используются выражения lambda, описанные в разделе Lambda. Обратите внимание, что выражение lambda — это всего лишь сокращение для упрощённого определения функции; функция, определённая в операторе «def», может передаваться или присваиваться другому имени так же, как и функция, определённая с помощью выражения lambda. Форма «def» фактически более мощная, так как она позволяет выполнять несколько операторов и аннотаций.

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

См. также

PEP 3107 - Аннотации функций

Исходное описание аннотаций функций.

PEP 484 - Тип подсказок

Определение стандартного значения для аннотаций: тип подсказки.

PEP 526 - Синтаксис для аннотаций переменных

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

PEP 563 - Отложенное вычисление аннотаций

Поддержка ссылок вперёд в аннотациях путём сохранения аннотаций в строковом виде во время выполнения вместо немедленного вычисления.

PEP 318 - Декораторы для функций и методов

Введены декораторы функций и методов. Классовые декораторы были введены в PEP 3129.

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

Определение класса создаёт объект класса (см. раздел Иерархия стандартных типов):

classdef    ::=  [decorators] "class" classname [type_params] [inheritance] ":" suite
inheritance ::=  "(" [argument_list] ")"
classname   ::=  identifier

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

class Foo:
    pass

эквивалентно

class Foo(object):
    pass

Затем тело класса выполняется в новой области выполнения (см. Имена и привязки), используя новое локальное пространство имён и исходное глобальное пространство имён. (Как правило, тело содержит в основном определения функций.) После завершения выполнения тела класса его область выполнения удаляется, но его локальное пространство имён сохраняется. [5] Затем создаётся объект класса, используя список наследования для базовых классов и сохранённое локальное пространство имён для словаря атрибутов. Имя класса привязывается к этому объекту класса в исходном локальном пространстве имён.

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

Создание класса может быть сильно настраиваемым с помощью метаклассов.

Классы также могут быть декорированы: так же, как при декорировании функций,

@f1(arg)
@f2
class Foo: pass

приблизительно эквивалентно

class Foo: pass
Foo = f1(arg)(f2(Foo))

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

Изменено в версии 3.9: Классы могут быть декорированы любым допустимым assignment_expression. Ранее грамматика была гораздо более ограниченной; см. PEP 614 для получения подробностей.

Список параметров типа может быть указан в квадратных скобках сразу после имени класса. Это указывает статическим анализаторам типов, что класс является обобщённым. Во время выполнения параметры типа можно получить из атрибута __type_params__ класса. Подробнее см. Обобщённые классы.

Изменено в версии 3.12: Список параметров типа появился в Python 3.12.

Примечание для программистов: Переменные, определённые в определении класса, являются атрибутами класса; они общие для экземпляров. Атрибуты экземпляров можно задавать в методе с помощью self.name = value. И атрибуты класса, и атрибуты экземпляров доступны с помощью обозначения «self.name», и атрибут экземпляра скрывает атрибут класса с тем же именем при обращении таким образом. Атрибуты класса могут использоваться в качестве значений по умолчанию для атрибутов экземпляров, но использование изменяемых значений там может привести к неожиданным результатам. Дескрипторы могут использоваться для создания переменных экземпляров с разными реализационными деталями.

См. также

PEP 3115 - Метаклассы в Python 3000

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

PEP 3129 - Декораторы классов

Предложение, которое добавило декораторы классов. Декораторы функций и методов были введены в PEP 318.

8.9. Корутины

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

8.9.1. Определение функции корутины

async_funcdef ::=  [decorators] "async" "def" funcname "(" [parameter_list] ")"
                   ["->" expression] ":" suite

Выполнение Python-корутин может приостанавливаться и возобновляться во многих точках (см. корутину). await выражения, async for и async with могут использоваться только в теле функции корутины.

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

Использование yield from выражения внутри тела функции корутины является SyntaxError.

Пример функции корутины:

async def func(param1, param2):
    do_stuff()
    await some_coroutine()

Изменено в версии 3.7: await и async теперь являются ключевыми словами; ранее они обрабатывались только как таковые внутри тела функции корутины.

8.9.2. Инструкция async for

async_for_stmt ::=  "async" for_stmt

Асинхронный итерируемый объект предоставляет метод __aiter__, который напрямую возвращает асинхронный итератор, который может вызывать асинхронный код в своём методе __anext__.

Инструкция async for позволяет удобно итерировать асинхронные итерируемые объекты.

Следующий код:

async for TARGET in ITER:
    SUITE
else:
    SUITE2

Семантически эквивалентен:

iter = (ITER)
iter = type(iter).__aiter__(iter)
running = True

while running:
    try:
        TARGET = await type(iter).__anext__(iter)
    except StopAsyncIteration:
        running = False
    else:
        SUITE
else:
    SUITE2

См. также __aiter__() и __anext__() для получения подробностей.

Использование инструкции async for за пределами тела функции корутины является SyntaxError.

8.9.3. Инструкция async with

async_with_stmt ::=  "async" with_stmt

Асинхронный менеджер контекста — это менеджер контекста, который может приостановить выполнение в своих методах enter и exit.

Следующий код:

async with EXPRESSION as TARGET:
    SUITE

семантически эквивалентен:

manager = (EXPRESSION)
aenter = type(manager).__aenter__
aexit = type(manager).__aexit__
value = await aenter(manager)
hit_except = False

try:
    TARGET = value
    SUITE
except:
    hit_except = True
    if not await aexit(manager, *sys.exc_info()):
        raise
finally:
    if not hit_except:
        await aexit(manager, None, None, None)

См. также __aenter__() и __aexit__() для получения подробностей.

Использование инструкции async with за пределами тела функции корутины является SyntaxError.

См. также

PEP 492 - Корутины с синтаксисом async и await

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

8.10. Списки параметров типа

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

Изменён в версии 3.13: Добавлена поддержка значений по умолчанию (см. PEP 696).

type_params  ::=  "[" type_param ("," type_param)* "]"
type_param   ::=  typevar | typevartuple | paramspec
typevar      ::=  identifier (":" expression)? ("=" expression)?
typevartuple ::=  "*" identifier ("=" expression)?
paramspec    ::=  "**" identifier ("=" expression)?

Функции (включая генераторы), классы и псевдонимы типов могут содержать список параметров типа:

def max[T](args: list[T]) -> T:
    ...

async def amax[T](args: list[T]) -> T:
    ...

class Bag[T]:
    def __iter__(self) -> Iterator[T]:
        ...

    def add(self, arg: T) -> None:
        ...

type ListOrSet[T] = list[T] | set[T]

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

Параметры типа объявляются в квадратных скобках ([]) сразу после имени функции, класса или псевдонима типа. Параметры типа доступны в области видимости обобщенного объекта, но не где-либо ещё. Таким образом, после объявления def func[T](): pass, имя T недоступно в области видимости модуля. Ниже описаны семантика обобщенных объектов более точно. Область видимости параметров типа моделируется специальной функцией (в техническом смысле, областью видимости аннотаций), которая оборачивает создание обобщенного объекта.

Обобщенные функции, классы и псевдонимы типов имеют атрибут __type_params__, перечисляющий их параметры типа.

Параметры типа бывают трёх типов:

  • typing.TypeVar, вводимые простым именем (например, T). Семантически это представляет собой один тип для проверяющего типа.
  • typing.TypeVarTuple, вводимые именем с префиксом из одного звёздочки (например, *Ts). Семантически это означает кортеж из любого количества типов.
  • typing.ParamSpec, вводимые именем с префиксом из двух звёздочек (например, **P). Семантически это означает параметры вызываемого объекта.

typing.TypeVar объявления могут определять пределы и ограничения с двоеточием (:) и выражением. Единственное выражение после двоеточия указывает на предел (например, T: int). Семантически это означает, что typing.TypeVar может представлять только типы, которые являются подтипом этого предела. Кортеж выражений в скобках после двоеточия указывает набор ограничений (например, T: (str, bytes)). Каждый член кортежа должен быть типом (снова, это не проверяется во время выполнения). Переменные типа с ограничениями могут принимать только один из типов в списке ограничений.

Для typing.TypeVar объявленных с помощью синтаксиса списка параметров типа, предел и ограничения не вычисляются при создании обобщенного объекта, а только при явном доступе к значению через атрибуты __bound__ и __constraints__. Для достижения этой цели пределы или ограничения вычисляются в отдельной области видимости аннотаций.

typing.TypeVarTuple и typing.ParamSpec не могут иметь пределов или ограничений.

Все три типа параметров также могут иметь значение по умолчанию, которое используется, когда параметр типа не указан явно. Это добавляется путем добавления одного знака равенства (=) и выражения. Как и пределы и ограничения переменных типа, значение по умолчанию не вычисляется при создании объекта, а только при доступе к атрибуту __default__ параметра типа. Для этого значение по умолчанию вычисляется в отдельной области видимости аннотаций. Если для параметра типа не указано значение по умолчанию, атрибут __default__ устанавливается в специальный объект-сентинель typing.NoDefault.

Следующий пример показывает полный набор разрешенных объявлений параметров типа:

def overly_generic[
   SimpleTypeVar,
   TypeVarWithDefault = int,
   TypeVarWithBound: int,
   TypeVarWithConstraints: (str, bytes),
   *SimpleTypeVarTuple = (int, float),
   **SimpleParamSpec = (str, bytearray),
](
   a: SimpleTypeVar,
   b: TypeVarWithDefault,
   c: TypeVarWithBound,
   d: Callable[SimpleParamSpec, TypeVarWithConstraints],
   *e: SimpleTypeVarTuple,
): ...

8.10.1. Обобщенные функции

Обобщенные функции объявляются следующим образом:

def func[T](arg: T): ...

Этот синтаксис эквивалентен:

annotation-def TYPE_PARAMS_OF_func():
    T = typing.TypeVar("T")
    def func(arg: T): ...
    func.__type_params__ = (T,)
    return func
func = TYPE_PARAMS_OF_func()

Здесь annotation-def обозначает область видимости аннотаций, которая фактически не связана с каким-либо именем во время выполнения. (В переводе сделана ещё одна уступка: синтаксис не проходит через доступ к атрибуту модуля typing, а создаёт экземпляр typing.TypeVar напрямую.)

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

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

@decorator
def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = some_default):
    ...

За исключением ленивой оценки предела TypeVar, это эквивалентно:

DEFAULT_OF_arg = some_default

annotation-def TYPE_PARAMS_OF_func():

    annotation-def BOUND_OF_T():
        return int
    # In reality, BOUND_OF_T() is evaluated only on demand.
    T = typing.TypeVar("T", bound=BOUND_OF_T())

    Ts = typing.TypeVarTuple("Ts")
    P = typing.ParamSpec("P")

    def func(*args: *Ts, arg: Callable[P, T] = DEFAULT_OF_arg):
        ...

    func.__type_params__ = (T, Ts, P)
    return func
func = decorator(TYPE_PARAMS_OF_func())

Заглавные имена, такие как DEFAULT_OF_arg фактически не связаны во время выполнения.

8.10.2. Обобщенные классы

Обобщенные классы объявляются следующим образом:

class Bag[T]: ...

Этот синтаксис эквивалентен:

annotation-def TYPE_PARAMS_OF_Bag():
    T = typing.TypeVar("T")
    class Bag(typing.Generic[T]):
        __type_params__ = (T,)
        ...
    return Bag
Bag = TYPE_PARAMS_OF_Bag()

Здесь снова annotation-def (не настоящее ключевое слово) обозначает область видимости аннотаций, и имя TYPE_PARAMS_OF_Bag не связано во время выполнения.

Обобщенные классы неявно наследуются от typing.Generic. Базовые классы и ключевые аргументы обобщенных классов вычисляются в области видимости типа для параметров типа, а декораторы вычисляются за пределами этой области видимости. Это иллюстрируется следующим примером:

@decorator
class Bag(Base[T], arg=T): ...

Это эквивалентно:

annotation-def TYPE_PARAMS_OF_Bag():
    T = typing.TypeVar("T")
    class Bag(Base[T], typing.Generic[T], arg=T):
        __type_params__ = (T,)
        ...
    return Bag
Bag = decorator(TYPE_PARAMS_OF_Bag())

8.10.3. Обобщённые псевдонимы типов

Оператор type также может использоваться для создания обобщённого псевдонима типа:

type ListOrSet[T] = list[T] | set[T]

За исключением отложенной оценки значения, это эквивалентно:

annotation-def TYPE_PARAMS_OF_ListOrSet():
    T = typing.TypeVar("T")

    annotation-def VALUE_OF_ListOrSet():
        return list[T] | set[T]
    # In reality, the value is lazily evaluated
    return typing.TypeAliasType("ListOrSet", VALUE_OF_ListOrSet(), type_params=(T,))
ListOrSet = TYPE_PARAMS_OF_ListOrSet()

Здесь annotation-def (не является реальным ключевым словом) указывает область применения аннотации. Заглавные имена, такие как TYPE_PARAMS_OF_ListOrSet фактически не привязаны во время выполнения.

Примечания

[1]

Исключение передаётся в стек вызовов, если нет finally блока, который случайно вызывает другое исключение. Это новое исключение приводит к потере предыдущего.

[2]

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

  • класс, который наследуется от collections.abc.Sequence
  • класс Python, который был зарегистрирован как collections.abc.Sequence
  • встроенный класс, у которого установлен бит (CPython) Py_TPFLAGS_SEQUENCE
  • класс, который наследуется от любого из вышеперечисленных

Следующие классы стандартной библиотеки являются последовательностями:

  • array.array
  • collections.deque
  • list
  • memoryview
  • range
  • tuple

Примечание

Значения темы типа str, bytes, и bytearray не соответствуют шаблонам последовательностей.

[3]

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

  • класс, который наследуется от collections.abc.Mapping
  • класс Python, который был зарегистрирован как collections.abc.Mapping
  • встроенный класс, у которого установлен бит (CPython) Py_TPFLAGS_MAPPING
  • класс, который наследуется от любого из вышеперечисленных

Классы стандартной библиотеки dict и types.MappingProxyType являются отображениями.

[4]

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

[5]

Строковая литерал, появляющаяся в качестве первого оператора в теле класса, преобразуется в элемент пространства имён __doc__ и, следовательно, в строку документации класса.

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

Spec-Zone.ru

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