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" assignment_expression ":" suite
             ("elif" assignment_expression ":" suite)*
             ["else" ":" suite]

Він вибирає точно один із наборів, обчислюючи вирази один за іншим, доки один не буде визнаний істинним (див. розділ Логічні операції для визначення істинного та хибного); тоді цей набір виконується (і жодна інша частина оператора if не виконується і не оцінюється). Якщо всі вирази хибні, виконується набір пропозиції else, якщо вона є.

8.2. Оператор while

Інструкція while використовується для повторного виконання, доки вираз є істинним:

while_stmt ::=  "while" assignment_expression ":" suite
                ["else" ":" suite]

Це багаторазово перевіряє вираз і, якщо воно вірне, виконує перший набір; якщо вираз є хибним (що може бути першим, коли його перевіряють), набір пропозиції else виконується, і цикл припиняється.

Інструкція break, виконана в першому наборі, завершує цикл без виконання набору речень else. Інструкція continue, виконана в першому наборі, пропускає решту пакета і повертається до перевірки виразу.

8.3. Оператор for

Оператор for використовується для повторення елементів послідовності (таких як рядок, кортеж або список) або іншого ітерованого об’єкта:

for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

The expression list is evaluated once; it should yield an iterable object. An iterator is created for the result of the expression_list. The suite is then executed once for each item provided by the iterator, in the order returned by the iterator. Each item in turn is assigned to the target list using the standard rules for assignments (see Заяви про призначення), and then the suite is executed. When the items are exhausted (which is immediately when the sequence is empty or an iterator raises a StopIteration exception), the suite in the else clause, if present, is executed, and the loop terminates.

Інструкція 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

Names in the target list are not deleted when the loop is finished, but if the sequence is empty, they will not have been assigned to at all by the loop. Hint: the built-in function range() returns an iterator of integers suitable to emulate the effect of Pascal’s for i := a to b do; e.g., list(range(3)) returns the list [0, 1, 2].

Примітка

There is a subtlety when the sequence is being modified by the loop (this can only occur for mutable sequences, e.g. lists). An internal counter is used to keep track of which item is used next, and this is incremented on each iteration. When this counter has reached the length of the sequence the loop terminates. This means that if the suite deletes the current (or a previous) item from the sequence, the next item will be skipped (since it gets the index of the current item which has already been treated). Likewise, if the suite inserts an item in the sequence before the current item, the current item will be treated again the next time through the loop. This can lead to nasty bugs that can be avoided by making a temporary copy using a slice of the whole sequence, e.g.,

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

8.4. Оператор try

The try statement specifies exception handlers and/or cleanup code for a group of statements:

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

The except clause(s) specify one or more exception handlers. When no exception occurs in the try clause, no exception handler is executed. When an exception occurs in the try suite, a search for an exception handler is started. This search inspects the except clauses in turn until one is found that matches the exception. An expression-less except clause, if present, must be last; it matches any exception. For an except clause with an expression, that expression is evaluated, and the clause matches the exception if the resulting object is «compatible» with the exception. An object is compatible with an exception if it is the class or a base class of the exception object, or a tuple containing an item that is the class or a base class of the exception object.

If no except clause matches the exception, the search for an exception handler continues in the surrounding code and on the invocation stack. 1

If the evaluation of an expression in the header of an except clause raises an exception, the original search for a handler is canceled and a search starts for the new exception in the surrounding code and on the call stack (it is treated as if the entire try statement raised the exception).

When a matching except clause is found, the exception is assigned to the target specified after the as keyword in that except clause, if present, and the except clause’s suite is executed. All except clauses must have an executable block. When the end of this block is reached, execution continues normally after the entire try statement. (This means that if two nested handlers exist for the same exception, and the exception occurs in the try clause of the inner handler, the outer handler will not handle the exception.)

When an exception has been assigned using as target, it is cleared at the end of the except clause. This is as if

except E as N:
    foo

було перекладено на:

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

This means the exception must be assigned to a different name to be able to refer to it after the except clause. Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs.

Before an except clause’s suite is executed, details about the exception are stored in the sys module and can be accessed via sys.exc_info(). sys.exc_info() returns a 3-tuple consisting of the exception class, the exception instance and a traceback object (see section Стандартна ієрархія типів) identifying the point in the program where the exception occurred. sys.exc_info() values are restored to their previous values (before the call) when returning from a function that handled an exception.

Необов’язкова пропозиція else виконується, якщо потік керування виходить із набору try, не було викликано винятків і немає return, continue або Інструкція break була виконана. Винятки в пункті else не обробляються попередніми пунктами except.

If finally is present, it specifies a „cleanup“ handler. The try clause is executed, including any except and else clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The finally clause is executed. If there is a saved exception it is re-raised at the end of the finally clause. If the finally clause raises another exception, the saved exception is set as the context of the new exception. If the finally clause executes a return, break or continue statement, the saved exception is discarded:

>>> def f():
...     try:
...         1/0
...     finally:
...         return 42
...
>>> f()
42

The exception information is not available to the program during execution of the finally clause.

When a return, break or continue statement is executed in the try suite of a tryfinally statement, the finally clause is also executed „on the way out.“

The return value of a function is determined by the last return statement executed. Since the finally clause always executes, a return statement executed in the finally clause will always be the last one executed:

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

Додаткову інформацію про винятки можна знайти в розділі Винятки, а інформацію про використання оператора raise для створення винятків можна знайти в розділі Оператор raise.

Змінено в версії 3.8: Prior to Python 3.8, a continue statement was illegal in the finally clause due to a problem with the implementation.

8.5. Оператор with

Оператор with використовується для обгортання виконання блоку методами, визначеними контекстним менеджером (див. розділ З менеджерами контексту операторів). Це дозволяє інкапсулювати загальні tryexceptfinally моделі використання для зручного повторного використання.

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

Виконання оператора with з одним «елементом» відбувається наступним чином:

  1. The context expression (the expression given in the with_item) is evaluated to obtain a context manager.

  2. The context manager’s __enter__() is loaded for later use.

  3. The context manager’s __exit__() is loaded for later use.

  4. The context manager’s __enter__() method is invoked.

  5. If a target was included in the with statement, the return value from __enter__() is assigned to it.

    Примітка

    The with statement guarantees that if the __enter__() method returns without an error, then __exit__() will always be called. Thus, if an error occurs during the assignment to the target list, it will be treated the same as an error occurring within the suite would be. See step 6 below.

  6. Сюїта виконана.

  7. The context manager’s __exit__() method is invoked. If an exception caused the suite to be exited, its type, value, and traceback are passed as arguments to __exit__(). Otherwise, three None arguments are supplied.

    If the suite was exited due to an exception, and the return value from the __exit__() method was false, the exception is reraised. If the return value was true, the exception is suppressed, and execution continues with the statement following the with statement.

    If the suite was exited for any reason other than an exception, the return value from __exit__() is ignored, and execution proceeds at the normal location for the kind of exit that was taken.

Наступний код:

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 - оператор «з».

Специфікація, передумови та приклади оператора Python with.

8.6. Визначення функцій

Визначення функції визначає об’єкт функції, визначений користувачем (див. розділ Стандартна ієрархія типів):

funcdef                   ::=  [decorators] "def" funcname "(" [parameter_list] ")"
                               ["->" expression] ":" suite
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

Визначення функції може бути обгорнуте одним або кількома виразами decorator. Вирази декоратора обчислюються, коли функція визначена в області видимості, яка містить визначення функції. Результат має бути викликаним, який викликається з об’єктом функції як єдиним аргументом. Повернене значення прив’язується до імені функції замість об’єкта функції. Кілька декораторів застосовуються вкладеним способом. Наприклад, такий код:

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

приблизно еквівалентно

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

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

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

Default parameter values are evaluated from left to right when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same «pre-computed» value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default value is in effect modified. This is generally not what was intended. A way around this is to use None as the default, and explicitly test for it in the body of the function, e.g.:

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.

Параметри можуть мати анотацію у формі «:вираз» після імені параметра. Будь-який параметр може мати анотацію, навіть у формі *ідентифікатор або **ідентифікатор. Функції можуть мати анотацію «повернення» у формі «-> вираз» після списку параметрів. Ці анотації можуть бути будь-яким дійсним виразом Python. Наявність анотацій не змінює семантику функції. Значення анотацій доступні як значення словника, ключ якого містить імена параметрів в атрибуті __annotations__ об’єкта функції. Якщо використовується імпорт анотацій із __future__, анотації зберігаються як рядки під час виконання, що дає змогу відкласти оцінку. В іншому випадку вони оцінюються під час виконання визначення функції. У цьому випадку анотації можуть оцінюватися в іншому порядку, ніж у вихідному коді.

Також можна створювати анонімні функції (функції, не прив’язані до імені) для негайного використання у виразах. Тут використовуються лямбда-вирази, описані в розділі Лямбда. Зауважте, що лямбда-вираз — це лише скорочення спрощеного визначення функції; функція, визначена в операторі «def», може бути передана або присвоєна іншому імені так само, як функція, визначена лямбда-виразом. Форма «def» насправді є потужнішою, оскільки вона дозволяє виконувати кілька операторів і анотацій.

Примітка програміста: Функції є об’єктами першого класу. Оператор «def», який виконується всередині визначення функції, визначає локальну функцію, яку можна повертати або передавати. Вільні змінні, які використовуються у вкладеній функції, можуть отримати доступ до локальних змінних функції, що містить def. Перегляньте розділ Називання та зв’язування для деталей.

Дивись також

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

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

PEP 484 - підказки типу

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

PEP 526 - Синтаксис для анотацій змінних

Ability to type hint variable declarations, including class variables and instance variables

PEP 563 - Відкладена оцінка анотацій

Підтримка прямих посилань в анотаціях завдяки збереженню анотацій у формі рядка під час виконання замість нетерплячої оцінки.

8.7. Визначення класів

Визначення класу визначає об’єкт класу (див. розділ Стандартна ієрархія типів):

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

Визначення класу є виконуваним оператором. Список успадкування зазвичай надає список базових класів (див. Метакласи для більш просунутого використання), тому кожен елемент у списку повинен оцінюватися як об’єкт класу, який дозволяє створювати підкласи. Класи без списку успадкування успадковують, за замовчуванням, від базового класу object; отже,

class Foo:
    pass

еквівалентно

class Foo(object):
    pass

Потім набір класів виконується в новому фреймі виконання (див. Називання та зв’язування), використовуючи щойно створений локальний простір імен і оригінальний глобальний простір імен. (Зазвичай набір містить в основному визначення функцій.) Коли набір класу завершує виконання, його кадр виконання відкидається, але його локальний простір імен зберігається. 3 Потім створюється об’єкт класу з використанням списку успадкування для базових класів і збереженого локального простору імен для словника атрибутів. Ім’я класу прив’язане до цього об’єкта класу в оригінальному локальному просторі імен.

Порядок, у якому атрибути визначені в тілі класу, зберігається в __dict__ нового класу. Зауважте, що це надійно лише відразу після створення класу та лише для класів, які були визначені за допомогою синтаксису визначення.

Створення класів можна значно налаштувати за допомогою metaclasses.

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

@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] ":" suite

Execution of Python coroutines can be suspended and resumed at many points (see coroutine). Inside the body of a coroutine function, await and async identifiers become reserved keywords; await expressions, async for and async with can only be used in coroutine function bodies.

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

Використання виразу yield from всередині тіла функції співпрограми є SyntaxError.

Приклад функції співпрограми:

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

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

async_for_stmt ::=  "async" for_stmt

An asynchronous iterable is able to call asynchronous code in its iter implementation, and asynchronous iterator can call asynchronous code in its next method.

The async for statement allows convenient iteration over asynchronous iterators.

Наступний код:

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

See also __aiter__() and __anext__() for details.

Це SyntaxError, якщо використовувати оператор async for поза тілом функції співпрограми.

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

async_with_stmt ::=  "async" with_stmt

Асинхронний менеджер контексту (asynchronous context manager) — це менеджер контексту (context manager),який може призупинити виконання своїх методів 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)

See also __aenter__() and __aexit__() for details.

Це SyntaxError, якщо використовувати оператор async with поза тілом функції співпрограми.

Дивись також

PEP 492 - Співпрограми з синтаксисом async і await

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

Виноски

1

Виняток поширюється на стек викликів, якщо немає пункту finally, який викликає інший виняток. Цей новий виняток призводить до втрати старого.

2

A string literal appearing as the first statement in the function body is transformed into the function’s __doc__ attribute and therefore the function’s docstring.

3

Рядковий літерал, що з’являється як перший оператор у тілі класу, перетворюється на елемент простору імен __doc__ і, отже, на docstring класу.