8. Составные заявления

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

Операторы 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]

Он выбирает ровно один из наборов, оценивая выражения по одному, пока одно из них не окажется истинным (см. раздел Булевы операции для определения true и false); затем этот набор выполняется (и никакая другая часть оператора 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" expression_list ":" suite
              ["else" ":" suite]

Список выражений оценивается один раз; в результате должен получиться итерабельный объект. Для результата expression_list создается итератор. Затем набор выполняется один раз для каждого элемента, предоставленного итератором, в порядке, возвращенном итератором. Каждый элемент по очереди присваивается целевому списку, используя стандартные правила присвоения (см. Ведомости заданий), а затем выполняется набор. Когда элементы исчерпаны (что происходит немедленно, если последовательность пуста или итератор выдает исключение StopIteration), выполняется набор в предложении 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() возвращает итератор целых чисел, подходящий для эмуляции эффекта паскалевской for i := a to b do; например, list(range(3)) возвращает список [0, 1, 2].

8.4. Оператор try

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

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

Пункт(ы) except задает один или несколько обработчиков исключений. Если в предложении try не встречается исключение, обработчик исключений не выполняется. Когда исключение возникает в наборе try, начинается поиск обработчика исключений. В ходе этого поиска поочередно проверяются предложения except, пока не будет найдено одно, соответствующее исключению. Пункт except без выражения, если он присутствует, должен быть последним; он соответствует любому исключению. Для пункта except, содержащего выражение, это выражение оценивается, и пункт соответствует исключению, если полученный объект «совместим» с исключением. Объект совместим с исключением, если объект является классом или non-virtual base class объекта исключения, или кортежем, содержащим элемент, который является классом или невиртуальным базовым классом объекта исключения.

Если ни одно предложение 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 и могут быть доступны через sys.exc_info(). sys.exc_info() возвращает три кортежа, состоящие из класса исключения, экземпляра исключения и объекта traceback (см. раздел Стандартная иерархия типов), определяющего место в программе, где произошло исключение. Данные об исключении, доступ к которым осуществляется через sys.exc_info(), восстанавливаются до прежних значений при выходе из обработчика исключений:

>>> print(sys.exc_info())
(None, None, None)
>>> try:
...     raise TypeError
... except:
...     print(sys.exc_info())
...     try:
...          raise ValueError
...     except:
...         print(sys.exc_info())
...     print(sys.exc_info())
...
(<class 'TypeError'>, TypeError(), <traceback object at 0x10efad080>)
(<class 'ValueError'>, ValueError(), <traceback object at 0x10efad040>)
(<class 'TypeError'>, TypeError(), <traceback object at 0x10efad080>)
>>> print(sys.exc_info())
(None, None, None)

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

Если присутствует 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 оператора tryfinally, пункт finally также выполняется «на выходе».

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

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

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

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

8.5. Оператор with

Возвращаемое значение функции определяется последним выполненным оператором with. Поскольку предложение С менеджерами по контексту заявлений всегда выполняется, оператор try, выполненный в предложении except, всегда будет последним выполненным:

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

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

  1. Выражение контекста (выражение, заданное в with_item) оценивается для получения менеджера контекста.

  2. Контекстный менеджер __enter__() загружается для последующего использования.

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

  4. Вызывается метод __enter__() контекстного менеджера.

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

    Примечание

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

  6. Набор выполняется.

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

    Если набор был завершен из-за исключения, а возвращаемое значение из метода __exit__() было false, исключение будет повторено. Если возвращаемое значение было истинным, исключение подавляется, и выполнение продолжается с оператора, следующего за оператором 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 - Утверждение «с»

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

8.6. Оператор match

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

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

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

Примечание

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

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

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

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

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

См.также

  • PEP 634 – Структурное сопоставление паттернов: спецификация

  • PEP 636 – Структурное сопоставление паттернов: учебник

8.6.1. Обзор

Вот обзор логического потока оператора сопоставления:

  1. Предметное выражение subject_expr оценивается, и в результате получается предметное значение. Если предметное выражение содержит запятую, то с помощью the standard rules строится кортеж.

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

    Примечание

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

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

    • Если защита оценивается как true или отсутствует, то выполняется block внутри case_block.

    • В противном случае выполняется попытка следующего case_block, как описано выше.

    • Если больше нет блоков case, оператор соответствия завершается.

Примечание

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

Образец заявления о соответствии:

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

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

8.6.2. Охрана

guard ::=  "if" named_expression

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

Логический поток блока case с блоком guard следующий:

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

  2. Если шаблон удался, оцените guard.

    • Если условие guard оценивается как истина, то выбирается блок case.

    • Если условие guard оценивается как false, блок case не выбирается.

    • Если guard вызывает исключение во время оценки, это исключение выводится на экран.

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

8.6.3. Неопровержимые аргументы

Неопровержимый блок прецедентов - это блок прецедентов, совпадающий со всеми. Оператор сопоставления может иметь не более одного неопровержимого блока прецедентов, и он должен быть последним.

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

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_pattern ::=  "|".closed_pattern+

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

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

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

8.6.4.2. AS Patterns

Шаблон 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. Буквальные узоры

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

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

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

Формы signed_number '+' NUMBER и signed_number '-' NUMBER предназначены для выражения complex numbers; они требуют вещественного числа слева и мнимого числа справа. Например, 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 ::=  '_'

_ является soft keyword внутри любого шаблона, но только внутри шаблонов. Он является идентификатором, как обычно, даже внутри match предметных выражений, guards и case блоков.

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

8.6.4.6. Ценностные паттерны

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

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

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

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

Примечание

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

8.6.4.7. Групповые узоры

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

group_pattern ::=  "(" pattern ")"

Проще говоря, (P) имеет тот же эффект, что и P.

8.6.4.8. Узоры последовательности

Шаблон последовательности содержит несколько подшаблонов для сопоставления с элементами последовательности. Синтаксис похож на распаковку списка или кортежа.

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

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

Примечание

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

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

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

  1. Если значение предмета не является последовательностью 2, шаблон последовательности не работает.

  2. Если значение субъекта является экземпляром str, bytes или bytearray, шаблон последовательности не работает.

  3. Последующие шаги зависят от того, является ли шаблон последовательности фиксированной или переменной длины.

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

    1. Если длина предметной последовательности не равна количеству подшаблонов, шаблон последовательности не работает

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

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

    1. Если длина предметной последовательности меньше, чем количество незвездных подпаттернов, шаблон последовательности терпит неудачу.

    2. Ведущие незвездные подшаблоны сопоставляются с соответствующими элементами, как для последовательностей фиксированной длины.

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

    4. Оставшиеся незвездные подпаттерны сопоставляются с соответствующими предметными элементами, как для последовательности фиксированной длины.

    Примечание

    Длина предметной последовательности получается через len() (т.е. по протоколу __len__()). Эта длина может кэшироваться интерпретатором аналогично value patterns.

Проще говоря, [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]

  • … и так далее для соответствующей пары KEY/шаблон.

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. После преобразования всех позиционных шаблонов в шаблоны ключевых слов,

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

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

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

Проще говоря, 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

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

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

примерно эквивалентно

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

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

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

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

Значения параметров по умолчанию оцениваются слева направо при выполнении определения функции. Это означает, что выражение оценивается один раз, когда функция определена, и что одно и то же «предварительно вычисленное» значение используется для каждого вызова. Это особенно важно понимать, когда значением параметра по умолчанию является изменяемый объект, такой как список или словарь: если функция изменяет объект (например, добавляет элемент в список), значение параметра по умолчанию фактически изменяется. Как правило, это не то, что было задумано. Способ обойти это - использовать 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.

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

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

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

См.также

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

Оригинальная спецификация для аннотаций функций.

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

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

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

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

PEP 563 - Отложенная оценка аннотаций

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

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

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

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

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

class Foo:
    pass

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

class Foo(object):
    pass

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

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

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

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

@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», причем атрибут экземпляра скрывает одноименный атрибут класса при таком обращении. Атрибуты класса могут использоваться в качестве значений по умолчанию для атрибутов экземпляра, но использование в них изменяемых значений может привести к неожиданным результатам. Descriptors можно использовать для создания переменных экземпляра с различными деталями реализации.

См.также

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

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

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

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

8.9. Корутины

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

8.9.1. Определение функции Coroutine

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

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

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

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

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

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

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

8.9.2. Оператор async for

async_for_stmt ::=  "async" for_stmt

asynchronous iterable предоставляет метод __aiter__, который непосредственно возвращает asynchronous iterator, который может вызывать асинхронный код в своем методе __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 вне тела функции coroutine является ошибкой async for.

8.9.3. Оператор async with

async_with_stmt ::=  "async" with_stmt

asynchronous context manager - это context manager, который способен приостановить выполнение в своих методах 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 вне тела функции coroutine является ошибкой async with.

См.также

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

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

Сноски

1

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

2

При сопоставлении образцов последовательность определяется как одно из следующих понятий:

  • класс, который наследуется от collections.abc.Sequence.

  • класс Python, который был зарегистрирован как collections.abc.Sequence.

  • встроенный класс, у которого установлен бит Py_TPFLAGS_SEQUENCE (CPython)

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

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

Примечание

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

3

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

  • класс, который наследуется от collections.abc.Mapping.

  • класс Python, который был зарегистрирован как collections.abc.Mapping.

  • встроенный класс, у которого установлен бит Py_TPFLAGS_MAPPING (CPython)

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

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

4

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

5

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

Вернуться на верх