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
                   | 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" `выражение_присваивания ` ":" набор
             ("elif" `выражение_присваивания ` ":" набор)*
             ["else" ":" набор]

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

8.2. Оператор while

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

while_stmt ::=  "while" `выражение_присваивания ` ":" набор
                ["else" ":" набор]

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

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

8.3. Оператор for

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

for_stmt ::=  "for" целевой_список "in" список_выражений ":" набор
              ["else" ":" набор]

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

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

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

for i in range(10):
    print(i)
    i = 5             # это не повлияет на цикл for
                      # потому что i будет перезаписан следующим
                      # индексом в range

Имена в целевом списке не удаляются после завершения цикла, но если последовательность пуста, они не будут присвоены циклом. Подсказка: встроенная функция range() возвращает итератор целых чисел, пригодный для эмуляции эффекта for i := a to b do Паскаля; например, list(range(3)) возвращает список [0, 1, 2].

Примечание

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

for x in a[:]:
    if x < 0: a.remove(x)

8.4. Оператор try

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

try_stmt  ::=  try1_stmt | try2_stmt
try1_stmt ::=  "try" ":" набор
               ("except" [выражение ["as" идентификатор]] ":" набор)+
               ["else" ":" набор]
               ["finally" ":" набор]
try2_stmt ::=  "try" ":" набор
               "finally" ":" набор

В предложении except указываются один или несколько обработчиков исключений. Если в предложении try не возникает исключения, обработчик исключения не вызывается. При возникновении исключения в наборе try запускается поиск обработчика исключения. Этот поиск по очереди проверяет предложения except до тех пор, пока они не будут найдено одно, соответствующее исключению. Предложение без выражения, если оно имеется, должно быть последним; оно соответствует любому исключению. Для предложения except с выражением вычисляется это выражение, и предложение соответствует исключению, если результирующий объект совместим с исключением. Объект совместим с исключением, если это класс или базовый класс объекта исключения или кортеж, содержащий элемент, который является классом или базовым классом объекта исключения.

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

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

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

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

except E as N:
    foo

был переведен к:

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

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

Перед выполнением набора предложений except сведения об исключении сохраняются в модуле sys и к ним можно получить доступ через sys.exc_info(). sys.exc_info() возвращает 3-кортеж, состоящий из класса исключения, сущности исключения и объекта трейсбэка (см. раздел Стандартная иерархия типов), идентифицирующего точку в программе, где произошло исключение. Значения sys.exc_info() восстанавливаются до своих предыдущих значений (до вызова) при возврате из функции, обработавшей исключение.

Необязательное предложение 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 используется для обёртывания выполнения блока методами, определенными менеджером контекста (см. раздел Оператор with контекстных менеджеров). Это позволяет инкапсулировать общие шаблоны использования try …:keyword:exceptfinally для удобства повторного использования.

with_stmt ::=  "with" with_item ("," with_item)* ":" набор
with_item ::=  expression ["as" цель]

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

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

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

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

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

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

    Примечание

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

  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

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

См.также

PEP 343 - Оператор «with»
Спецификация, предыстория и примеры для Python оператора with.

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

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

funcdef                   ::=  [decorators] "def" funcname "(" [parameter_list] ")"
                               ["->" expression] ":" набор
decorators                ::=  decorator+
decorator                 ::=  "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE
dotted_name               ::=  identifier ("." identifier)*
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

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

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

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

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

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

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

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

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

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

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("собственность зоопарка")
    return penguin

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

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

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

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

См.также

PEP 3107 - Аннотации функций
Исходная спецификация для аннотаций функций.
PEP 484 - Подсказки типа
Определение стандартного значения для аннотаций: подсказки типа.
PEP 526 - Синтаксис для аннотаций к переменным
Возможность ввода объявлений подсказок к переменным, включая переменные класса и переменные сущности.
PEP 563 - Отложенная оценка аннотаций
Поддержка прямых ссылок в аннотациях путем сохранения аннотаций в строковой форме во время выполнения, вместо активного вычисления.

8.7. Определения класса

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

classdef    ::=  [decorators] "class" classname [inheritance] ":" набор
inheritance ::=  "(" [argument_list] ")"
classname   ::=  identifier

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

class Foo:
    pass

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

class Foo(object):
    pass

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

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

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

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

@f1(arg)
@f2
class Foo: pass

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

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

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

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

См.также

PEP 3115 - Метаклассы в Python 3000
Предложение, которое изменило определение метаклассов на текущий синтаксис и семантику для построения классов с метаклассами.
PEP 3129 - Декораторы класса
Предложение о добавлении декораторов классов. Декораторы функций и методов были представлены в PEP 318.

8.8. Корутины

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

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

async_funcdef ::=  [decorators] "async" "def" funcname "(" [parameter_list] ")"
                   ["->" expression] ":" набор

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

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

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

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

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

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

async_for_stmt ::=  "async" for_stmt

Асинхронный итератор может вызвать асинхронный код в iter реализации, а асинхронный итератор может вызвать асинхронный код в своём следующем методе.

Оператор 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.8.3. Оператор async with

async_with_stmt ::=  "async" with_stmt

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

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

async with EXPRESSION as TARGET:
    SUITE

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

manager = (EXPRESSION)
aexit = type(manager).__aexit__
aenter = type(manager).__aenter__
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]Строковый литерал, появляющийся в качестве первого оператора в теле функции преобразуется в атрибут __doc__ функции и поэтому в строку документации функции.
[3]Строковый литерал, появляющийся в качестве первого оператора в теле класса преобразуется в элемент __doc__ пространства имён и поэтому в строку документации класса.