Spec-Zone.ru › Python 3.12

Составные инструкции

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

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

Если инструкция 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

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

Логика выполнения блока case с guard выглядит следующим образом:

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

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

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

8.6.3. Неопровержимые блоки 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

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

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.

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

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

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 не может быть границ или ограничений.

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

def overly_generic[
   SimpleTypeVar,
   TypeVarWithBound: int,
   TypeVarWithConstraints: (str, bytes),
   *SimpleTypeVarTuple,
   **SimpleParamSpec,
](
   a: SimpleTypeVar,
   b: TypeVarWithBound,
   c: Callable[SimpleParamSpec, TypeVarWithConstraints],
   *d: 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.12/reference/compound_stmts.html

Spec-Zone.ru

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