Модель выполнения
4.1. Структура программы
Программа на Python состоит из блоков кода. Блок — это фрагмент текста программы на Python, который выполняется как единое целое. К блокам относятся модуль, тело функции и определение класса. Каждая команда, введённая в интерактивном режиме, является блоком. Файл сценария (файл, переданный интерпретатору через стандартный ввод или указанный в качестве аргумента командной строки интерпретатора) является блоком кода. Команда сценария (команда, указанная в командной строке интерпретатора с параметром -c) является блоком кода. Модуль, запущенный из командной строки как сценарий верхнего уровня (как модуль __main__) с помощью аргумента -m, также является блоком кода. Строковый аргумент, переданный встроенным функциям eval() и exec(), является блоком кода.
Блок кода выполняется в кадре выполнения. Кадр содержит некоторую административную информацию (используемую для отладки) и определяет, где и как продолжается выполнение после завершения блока кода.
4.2. Именование и связывание
4.2.1. Связывание имён
Имена ссылаются на объекты. Имена вводятся операциями связывания имён.
Имена связывают следующие конструкции:
- формальные параметры функций,
- определения классов,
- определения функций,
- выражения присваивания,
- цели, являющиеся идентификаторами и встречающиеся в присваивании:
-
forв заголовке цикла, - после
asв инструкцииwith, в блокеexcept, в блокеexcept*или в шаблоне as при сопоставлении со структурным шаблоном, - в шаблоне захвата при сопоставлении со структурным шаблоном
-
инструкции
import. -
инструкции
type. - списки параметров типа.
Инструкция import вида from ... import * связывает все имена, определённые в импортированном модуле, кроме тех, которые начинаются с символа подчёркивания. Эту форму можно использовать только на уровне модуля.
Для этих целей целью, встречающейся в инструкции del, также считается связанное имя (хотя фактическая семантика заключается в отвязывании имени).
Каждая инструкция присваивания или импорта находится внутри блока, определённого классом или функцией, либо на уровне модуля (в блоке кода верхнего уровня).
Если имя связано в блоке, оно является локальной переменной этого блока, если только оно не объявлено как nonlocal или global. Если имя связано на уровне модуля, оно является глобальной переменной. (Переменные блока кода модуля являются локальными и глобальными.) Если переменная используется в блоке кода, но не определена в нём, она является свободной переменной.
Каждое вхождение имени в тексте программы ссылается на связывание этого имени, установленное следующими правилами разрешения имён.
4.2.2. Разрешение имён
Область видимости определяет видимость имени внутри блока. Если в блоке определена локальная переменная, её область видимости включает этот блок. Если определение находится в блоке функции, область видимости распространяется на любые блоки, содержащиеся в этом блоке, если только вложенный блок не вводит для этого имени другое связывание.
При использовании имени в блоке кода оно разрешается с учётом ближайшей охватывающей области видимости. Совокупность всех областей видимости, видимых блоку кода, называется окружением блока.
Если имя нигде не найдено, возбуждается исключение NameError. Если текущая область видимости является областью функции, а имя относится к локальной переменной, которой ещё не присвоено значение к моменту использования имени, возбуждается исключение UnboundLocalError. UnboundLocalError является подклассом NameError.
Если операция связывания имени встречается где-либо в блоке кода, все использования этого имени в блоке считаются ссылками на текущий блок. Это может привести к ошибкам, если имя используется в блоке до того, как оно связано. Это правило неочевидно. В Python нет объявлений, и операции связывания имени могут встречаться где угодно в блоке кода. Локальные переменные блока кода можно определить, просканировав весь текст блока на наличие операций связывания имён. Примеры см. в ответе на часто задаваемый вопрос об UnboundLocalError.
Если в блоке встречается инструкция global, все использования указанных в ней имён ссылаются на связывания этих имён в пространстве имён верхнего уровня. Имена разрешаются в пространстве имён верхнего уровня путём поиска в глобальном пространстве имён, то есть в пространстве имён модуля, содержащего блок кода, и в пространстве имён встроенных объектов — пространстве имён модуля builtins. Сначала выполняется поиск в глобальном пространстве имён. Если имена там не найдены, поиск продолжается в пространстве имён встроенных объектов. Если имена не найдены и там, в глобальном пространстве имён создаются новые переменные. Инструкция global должна предшествовать всем использованиям перечисленных имён.
Инструкция global имеет ту же область видимости, что и операция связывания имени в том же блоке. Если ближайшая охватывающая область видимости свободной переменной содержит инструкцию global, свободная переменная считается глобальной.
Инструкция nonlocal указывает, что соответствующие имена ссылаются на ранее связанные переменные в ближайшей охватывающей области видимости функции. Если указанное имя не существует ни в одной охватывающей области видимости функции, во время компиляции возбуждается исключение SyntaxError. Параметры типа нельзя повторно связывать с помощью инструкции nonlocal.
Пространство имён модуля автоматически создаётся при первом импорте модуля. Главный модуль сценария всегда называется __main__.
Блоки определения классов и аргументы exec() и eval() имеют особенности в контексте разрешения имён. Определение класса — это исполняемая инструкция, которая может использовать и определять имена. Для этих ссылок применяются обычные правила разрешения имён, за исключением того, что несвязанные локальные переменные ищутся в глобальном пространстве имён. Пространство имён определения класса становится словарём атрибутов класса. Область видимости имён, определённых в блоке класса, ограничена этим блоком; она не распространяется на блоки кода методов. Это относится к включениям и генераторным выражениям, но не к областям видимости аннотаций, которым доступны охватывающие их области видимости классов. Это означает, что следующий код завершится ошибкой:
class A:
a = 42
b = list(a + i for i in range(10))
Однако следующий код выполнится успешно:
class A:
type Alias = Nested
class Nested: pass
print(A.Alias.__value__) # <type 'A.Nested'>
4.2.3. Области видимости аннотаций
Списки параметров типа и инструкции type создают области видимости аннотаций, которые в основном ведут себя как области видимости функций, но имеют некоторые описанные ниже исключения. В настоящее время аннотации не используют области видимости аннотаций, однако ожидается, что в Python 3.13 они будут их использовать после реализации PEP 649.
Области видимости аннотаций используются в следующих контекстах:
- Списки параметров типа для обобщённых псевдонимов типов.
- Списки параметров типа для обобщённых функций. Аннотации обобщённой функции выполняются в области видимости аннотаций, а значения по умолчанию и декораторы — нет.
- Списки параметров типа для обобщённых классов. Базовые классы и ключевые аргументы обобщённого класса выполняются в области видимости аннотаций, а декораторы — нет.
- Ограничения, условия и значения по умолчанию параметров типа (вычисляются лениво).
- Значения псевдонимов типов (вычисляются лениво).
Области видимости аннотаций отличаются от областей видимости функций следующим образом:
- Областям видимости аннотаций доступны пространства имён охватывающих их классов. Если область видимости аннотаций находится непосредственно внутри области видимости класса или внутри другой области видимости аннотаций, которая сама находится непосредственно внутри области видимости класса, код в области видимости аннотаций может использовать имена, определённые в области видимости класса, как если бы он выполнялся непосредственно в теле класса. В отличие от этого, обычные функции, определённые внутри классов, не могут обращаться к именам, определённым в области видимости класса.
- Выражения в областях видимости аннотаций не могут содержать выражения
yield,yield from,awaitили:=. (Эти выражения разрешены в других областях видимости, вложенных в область видимости аннотаций.) - Имена, определённые в областях видимости аннотаций, нельзя повторно связывать с помощью инструкций
nonlocalво внутренних областях видимости. Это относится только к параметрам типа, поскольку никакие другие синтаксические элементы, которые могут встречаться в областях видимости аннотаций, не вводят новые имена. - Хотя у областей видимости аннотаций есть внутреннее имя, оно не отражается в квалифицированном имени объектов, определённых в этой области. Вместо этого значение атрибута
__qualname__таких объектов соответствует случаю, если бы объект был определён в охватывающей области видимости.
Добавлено в версии 3.12: Области видимости аннотаций появились в Python 3.12 в рамках PEP 695.
Изменено в версии 3.13: Области видимости аннотаций также используются для значений параметров типа по умолчанию, как предусмотрено в PEP 696.
4.2.4. Ленивое вычисление
Значения псевдонимов типов, созданных с помощью инструкции type, вычисляются лениво. То же относится к ограничениям, условиям и значениям по умолчанию переменных типа, созданных с помощью синтаксиса параметров типа. Это означает, что они не вычисляются при создании псевдонима типа или переменной типа. Вместо этого они вычисляются только тогда, когда это необходимо для разрешения обращения к атрибуту.
Пример:
>>> type Alias = 1/0 >>> Alias.__value__ Traceback (most recent call last): ... ZeroDivisionError: division by zero >>> def func[T: 1/0](): pass >>> T = func.__type_params__[0] >>> T.__bound__ Traceback (most recent call last): ... ZeroDivisionError: division by zero
В этом примере исключение возбуждается только при обращении к атрибуту __value__ псевдонима типа или атрибуту __bound__ переменной типа.
Такое поведение особенно полезно при ссылках на типы, которые ещё не определены на момент создания псевдонима типа или переменной типа. Например, ленивое вычисление позволяет создавать взаимно рекурсивные псевдонимы типов:
from typing import Literal
type SimpleExpr = int | Parenthesized
type Parenthesized = tuple[Literal["("], Expr, Literal[")"]]
type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], Expr]
Лениво вычисляемые значения вычисляются в области видимости аннотаций, а это означает, что имена внутри лениво вычисляемого значения ищутся так, как если бы они использовались в непосредственно охватывающей области видимости.
Добавлено в версии 3.12.
4.2.5. Встроенные объекты и ограниченное выполнение
Особенность реализации CPython: Пользователям не следует обращаться к __builtins__; это исключительно деталь реализации. Тем, кто хочет переопределить значения в пространстве имён встроенных объектов, следует import модуль builtins и соответствующим образом изменить его атрибуты.
Пространство имён встроенных объектов, связанное с выполнением блока кода, фактически определяется поиском имени __builtins__ в его глобальном пространстве имён; это должен быть словарь или модуль (в последнем случае используется словарь модуля). По умолчанию в модуле __main__ __builtins__ — это встроенный модуль builtins; во всех остальных модулях __builtins__ является псевдонимом словаря самого модуля builtins.
4.2.6. Взаимодействие с динамическими возможностями
Разрешение имён свободных переменных происходит во время выполнения, а не во время компиляции. Это означает, что следующий код выведет число 42:
i = 10
def f():
print(i)
i = 42
f()
Функции eval() и exec() не имеют доступа ко всему окружению, необходимому для разрешения имён. Имена могут разрешаться в локальных и глобальных пространствах имён вызывающего кода. Свободные переменные разрешаются не в ближайшем охватывающем пространстве имён, а в глобальном пространстве имён. [1] Функции exec() и eval() имеют необязательные аргументы, позволяющие переопределить глобальное и локальное пространства имён. Если указано только одно пространство имён, оно используется для обоих.
4.3. Исключения
Исключения позволяют выйти из обычного потока управления блоком кода, чтобы обработать ошибки или другие исключительные ситуации. Исключение возбуждается в месте обнаружения ошибки; оно может быть обработано окружающим блоком кода или любым блоком кода, который прямо или косвенно вызвал блок, в котором произошла ошибка.
Интерпретатор Python возбуждает исключение при обнаружении ошибки времени выполнения (например, деления на ноль). Программа на Python также может явно возбудить исключение с помощью инструкции raise. Обработчики исключений задаются инструкцией try … except. Блок finally такой инструкции можно использовать для указания кода очистки, который не обрабатывает исключение, но выполняется независимо от того, произошло ли исключение в предшествующем коде.
В Python используется модель обработки ошибок с «завершением»: обработчик исключения может выяснить, что произошло, и продолжить выполнение на внешнем уровне, но не может устранить причину ошибки и повторить неудачную операцию (кроме как повторно войдя в проблемный фрагмент кода с самого начала).
Если исключение вообще не обработано, интерпретатор прекращает выполнение программы или возвращается в интерактивный главный цикл. В обоих случаях он выводит трассировку стека, кроме случаев, когда исключением является SystemExit.
Исключения идентифицируются экземплярами классов. Блок except выбирается в зависимости от класса экземпляра: в нём должен быть указан класс экземпляра или его невиртуальный базовый класс. Экземпляр может быть передан обработчику и содержать дополнительные сведения об исключительной ситуации.
Примечание
Тексты сообщений об исключениях не являются частью API Python. Их содержимое может измениться без предупреждения при переходе с одной версии Python на другую, поэтому код, который будет выполняться в нескольких версиях интерпретатора, не должен полагаться на эти сообщения.
См. также описание инструкции try в разделе Инструкция try и инструкции raise в разделе Инструкция raise.
Сноски
© 2001–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/reference/executionmodel.html