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* задают один или несколько обработчиков групп исключений (экземпляров BaseExceptionGroup). Инструкция try может содержать либо части except, либо части except*, но не те и другие одновременно. В случае except* тип исключения для сопоставления обязателен, поэтому except*: является синтаксической ошибкой. Тип интерпретируется так же, как в случае except, но сопоставление выполняется с исключениями, содержащимися в обрабатываемой группе. Возникает исключение TypeError, если сопоставляемый тип является подклассом BaseExceptionGroup, поскольку это привело бы к неоднозначной семантике.

Когда в блоке try возникает группа исключений, каждая часть except* разделяет её (см. split()) на подгруппы подходящих и неподходящих исключений. Если подгруппа подходящих исключений не пуста, она становится обрабатываемым исключением (значением, возвращаемым sys.exception()) и присваивается цели части except* (если она есть). Затем выполняется тело части except*. Если подгруппа неподходящих исключений не пуста, она обрабатывается следующей частью except* тем же способом. Процесс продолжается, пока не будут сопоставлены все исключения в группе или не выполнится последняя часть 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 "<doctest default[0]>", line 2, in <module>
  |     raise ExceptionGroup("eg",
  |         [ValueError(1), TypeError(2), OSError(3), OSError(4)])
  | ExceptionGroup: eg (1 sub-exception)
  +-+---------------- 1 ----------------
    | ValueError: 1
    +------------------------------------

Если исключение, возникшее в блоке try, не является группой исключений и его тип соответствует одной из частей except*, оно перехватывается и оборачивается в группу исключений с пустой строкой в качестве сообщения. Это гарантирует, что тип цели e всегда будет BaseExceptionGroup:

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

Инструкции 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 программе недоступна информация об исключении.

Если инструкция return, break или continue выполняется в блоке try инструкции try…finally, часть 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). Это позволяет оформить типичные шаблоны использования 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__() будет вызван в любом случае. Поэтому ошибка, возникшая при присваивании целевому списку, обрабатывается так же, как ошибка, возникшая внутри блока. См. шаг 7 ниже.

  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)
hit_except = False

try:
    TARGET = value
    SUITE
except:
    hit_except = True
    if not exit(manager, *sys.exc_info()):
        raise
finally:
    if not hit_except:
        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»

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

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. Если образец успешно сопоставлен, вычисляется соответствующее условие (если оно присутствует). В этом случае гарантируется, что все имена уже привязаны.

    • Если условие вычисляется как истинное или отсутствует, выполняется 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 истинно, выбирается блок case.
    • Если условие guard ложно, блок case не выбирается.
    • Если при вычислении guard возникает исключение, оно передаётся выше.

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

8.6.3. Безусловные блоки case

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

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

  • Образцы AS, левая часть которых является безусловной
  • Образцы OR, содержащие как минимум один безусловный образец
  • Образцы захвата
  • Образцы-шаблоны
  • заключённые в скобки безусловные образцы

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

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

8.6.4.1. Образцы OR

Образец OR состоит из двух или более образцов, разделённых вертикальными чертами |. Синтаксис:

or_pattern ::= "|".closed_pattern+

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

Образец OR последовательно сопоставляет каждый из своих подобразцов со значением субъекта, пока один из них не подойдёт. В этом случае образец OR считается успешным. Если ни один из подобразцов не подошёл, образец OR считается неуспешным.

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

8.6.4.2. Образцы AS

Образец AS сопоставляет образец OR слева от ключевого слова as с субъектом. Синтаксис:

as_pattern ::= or_pattern "as" capture_pattern

Если образец OR не подошёл, образец AS считается неуспешным. В противном случае образец AS связывает субъект с именем справа от ключевого слова 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

Примечание

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

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>[1] (обратите внимание, что при этом сопоставлении также могут связываться имена)
  • … и так далее для соответствующей пары образец/элемент.

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_star_kwargs]]
                              | "*" ("," defparameter)+ ["," [parameter_star_kwargs]]
                              | parameter_star_kwargs
parameter_star_kwargs     ::= "**" 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.

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

Примечание для программистов: Функции — объекты первого класса. Инструкция «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
  • встроенный класс, у которого установлен бит Py_TPFLAGS_SEQUENCE (CPython)
  • класс, наследующий от любого из перечисленных выше

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

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

Примечание

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

[3]

При сопоставлении с образцом отображением считается один из следующих объектов:

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

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

[4]

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

[5]

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

© 2001–2025 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