Spec-Zone.ru › Python 3.11

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

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

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

Составная инструкция состоит из одной или нескольких «ветвей» (clauses). Ветвь состоит из заголовка и «блока» (suite). Заголовки ветвей конкретной составной инструкции находятся на одном и том же уровне отступа. Заголовок каждой ветви начинается с уникального идентифицирующего ключевого слова и заканчивается двоеточием. Блок — это группа инструкций, управляемая ветвью. Блок может представлять собой одну или несколько простых инструкций, разделенных точкой с запятой, расположенных на той же строке, что и заголовок, после его двоеточия, либо одну или несколько инструкций с отступом на последующих строках. Только последняя форма блока может содержать вложенные составные инструкции; следующий пример является недопустимым главным образом потому, что было бы неясно, к какой ветви 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 не соответствует исключению, поиск обработчика исключений продолжается в окружающем коде и в стеке вызовов. [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. Исключения очищаются, потому что вместе с прикрепленным к ним трассировочным стеком (traceback) они образуют циклическую ссылку с кадром стека, сохраняя все локальные переменные в этом кадре активными до тех пор, пока не произойдет следующая сборка мусора.

Перед выполнением блока ветви 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*.

Начиная с версии 3.11.4, если вся группа ExceptionGroup обработана и из ветви except* возникает только одно исключение, это исключение больше не оборачивается для создания нового объекта ExceptionGroup.

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

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

Ветвь except* должна иметь тип для сопоставления, и этот тип не может быть подклассом BaseExceptionGroup. Нельзя смешивать 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 с одним элементом («item») происходит следующим образом:

  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 используется для сопоставления с образцом (pattern matching). Синтаксис:

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

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

8.6.2. Условия-стражи (Guards)

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

Неопровержимый (irrefutable) блок case — это блок, сопоставляемый с любым значением. Инструкция match может иметь не более одного неопровержимого блока case, и он должен быть последним.

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

  • Шаблоны AS, левая часть которых неопровержима
  • Шаблоны OR, содержащие хотя бы один неопровержимый шаблон
  • Шаблоны захвата (Capture Patterns)
  • Шаблоны подстановки (Wildcard Patterns)
  • заключенные в скобки неопровержимые шаблоны

8.6.4. Шаблоны

Примечание

В этом разделе используются грамматические обозначения, выходящие за рамки стандартной РБНФ (EBNF):

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

Синтаксис верхнего уровня для 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 | "-" NUMBER

Правило strings и токен NUMBER определены в стандартной грамматике Python. Поддерживаются строки в тройных кавычках. Поддерживаются «сырые» строки (raw strings) и байтовые строки. 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 "(" [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   ::=  "*" [parameter] ("," defparameter)* ["," ["**" parameter [","]]]
                               | "**" parameter [","]
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.

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

Значения параметров по умолчанию вычисляются слева направо при выполнении определения функции. Это означает, что выражение вычисляется один раз, когда функция определяется, и одно и то же «предварительно вычисленное» значение используется для каждого вызова. Это особенно важно понимать, когда значение параметра по умолчанию является изменяемым объектом, таким как список или словарь: если функция изменяет объект (например, путем добавления элемента в список), значение параметра по умолчанию фактически изменяется. Обычно это не то, что предполагалось. Способ обойти это — использовать 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. Функции могут иметь аннотацию возвращаемого значения вида «-> expression» после списка параметров. Эти аннотации могут быть любым допустимым выражением Python. Наличие аннотаций не меняет семантику функции. Значения аннотаций доступны в виде значений словаря, ключами которого являются имена параметров, в атрибуте __annotations__ объекта функции. Если используется импорт annotations из __future__, аннотации сохраняются как строки во время выполнения, что позволяет отложить вычисление. В противном случае они вычисляются при выполнении определения функции. В этом случае аннотации могут вычисляться в порядке, отличном от порядка их появления в исходном коде.

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

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

См. также

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

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

PEP 484 - Подсказки типов

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

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

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

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

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

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

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

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

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

classdef    ::=  [decorators] "class" classname [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.

Примечание для программиста: Переменные, определенные в определении класса, являются атрибутами класса; они разделяются всеми экземплярами. Атрибуты экземпляра могут быть установлены в методе с помощью 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.

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

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

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

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

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

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

См. также

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

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

Сноски

[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__ и, следовательно, в строку документации (docstring) функции.

[5]

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

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

Spec-Zone.ru

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