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 INDENTstatement
+ 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
оператора try
…finally
, предложение finally
также выполняется «при выходе».
Возвращаемое значение функции определяется последним выполненным оператором
return
. Так как предложение finally
всегда выполняется, оператор
return
выполняемый в предложении finally
, всегда будет
последним выполненным:
>>> def foo():
... try:
... return 'try'
... finally:
... return 'finally'
...
>>> foo()
'finally'
Дополнительную информацию об исключениях можно найти в разделе Исключения, а
информацию об использовании оператора raise
для генерации исключений
можно найти в разделе Оператор raise.
8.5. Оператор with
¶
Оператор with
используется для обёртывания выполнения блока
методами, определенными менеджером контекста (см. раздел Оператор with контекстных менеджеров).
Это позволяет инкапсулировать общие шаблоны использования
try
…:keyword:except…finally
для удобства
повторного использования.
with_stmt ::= "with"with_item
(","with_item
)* ":"набор
with_item ::=expression
["as"цель
]
Выполнение оператора with
с одним «элементом» происходит следующим
образом
Выражение контекста (выражение, указанное в
with_item
) вычисляется для получения менеджера контекста.Загружается
__enter__()
менеджера контекста для дальнейшего использования.Загружается
__exit__()
менеджера контекста для дальнейшего использования.Вызывается метод
__enter__()
менеджера контекста.Если целевой объект был включен в оператор
with
, ему присваивается возвращаемое значение из__enter__()
.Примечание
Оператор
with
гарантирует, что если__enter__()
метод вернется без ошибки, то всегда будет вызываться__exit__()
. Таким образом, если ошибка возникает во время назначения целевому списку, она будет обрабатываться так же, как и ошибка, возникающая в наборе. См. шаг 6 ниже.Набор выполнен.
Вызывается метод менеджера контекст
__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: Поддержка нескольких контекстных выражений.
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
,», а атрибут сущности скрывает
атрибут класса с тем же именем при таком обращении. Атрибуты класса могут
использоваться по умолчанию для атрибутов экземпляра, но использование изменяемых
значений может привести к неожиданным результатам. Дескрипторы
могут использоваться для создания переменных экземпляра с различными деталями
реализации.
См.также
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__ пространства имён и поэтому в строку
документации класса. |