Модель выполнения
4.1. Структура программы
Программа Python строится из блоков кода. Блок — это часть текста программы Python, выполняемая как единица. К блокам относятся: модуль, тело функции и определение класса. Каждая команда, введённая интерактивно, является блоком. Файл скрипта (файл, переданный в качестве стандартного ввода интерпретатору или указанный в качестве аргумента командной строки интерпретатору) представляет собой блок кода. Команда скрипта (команда, указанная в командной строке интерпретатора с опцией -c) также является блоком кода. Модуль, запущенный как скрипт верхнего уровня (как модуль __main__) из командной строки с помощью аргумента -m, также является блоком кода. Строковый аргумент, передаваемый встроенным функциям eval() и exec(), является блоком кода.
Блок кода выполняется в кадре выполнения. Кадр содержит некоторую административную информацию (используемую для отладки) и определяет, где и как выполнение продолжается после завершения выполнения блока кода.
4.2. Имена и привязки
4.2.1. Привязка имён
Имена ссылаются на объекты. Имена вводятся операциями привязки имён.
Следующие конструкции привязывают имена:
- формальные параметры функций,
- определения классов,
- определения функций,
- выражения присваивания,
-
цели, которые являются идентификаторами, если они встречаются в операторе присваивания:
-
importоператоры. -
typeоператоры. - списки параметров типа.
Оператор import вида from ... import * привязывает все имена, определенные в импортированном модуле, за исключением тех, которые начинаются с подчеркивания. Этот вид может использоваться только на уровне модуля.
Целевая переменная, используемая в операторе del, также считается связанной для этой цели (хотя фактическая семантика заключается в разрыве привязки имени).
Каждый оператор присваивания или импорта находится внутри блока, определенного с помощью определения класса или функции, или на уровне модуля (блок кода верхнего уровня).
Если имя привязано в блоке, оно является локальной переменной этого блока, если не объявлено как nonlocal или global. Если имя привязано на уровне модуля, оно является глобальной переменной. (Переменные блока кода модуля являются локальными и глобальными). Если переменная используется в блоке кода, но не определена в нём, она является свободной переменной.
Каждое использование имени в тексте программы относится к привязке этого имени, установленной следующими правилами разрешения имён.
4.2.2. Разрешение имён
Область видимости определяет видимость имени внутри блока. Если локальная переменная определена в блоке, её область видимости включает этот блок. Если определение происходит в блоке функции, область видимости распространяется на любые блоки, содержащиеся в определяющем блоке, если содержащийся блок не вводит другое привязывание для имени.
Когда имя используется в блоке кода, оно разрешается с использованием ближайшей вложенной области видимости. Набор всех таких областей видимости, видимых блоком кода, называется окружением блока.
Если имя вообще не найдено, возникает исключение NameError. Если текущая область видимости является областью видимости функции, и имя относится к локальной переменной, которая ещё не была связана со значением в момент использования имени, возникает исключение UnboundLocalError. UnboundLocalError является подклассом NameError.
Если операция привязки имени происходит где-либо в блоке кода, все использования имени внутри блока обрабатываются как ссылки на текущий блок. Это может привести к ошибкам, когда имя используется в блоке до того, как оно будет привязано. Это правило тонкое. Python не имеет объявлений и позволяет операциям привязки имён происходить где угодно в блоке кода. Локальные переменные блока кода могут быть определены путём сканирования всего текста блока на предмет операций привязки имени. См. статью FAQ по UnboundLocalError для примеров.
Если оператор global встречается в блоке, все использования имён, указанных в операторе, относятся к привязкам этих имён в пространстве имён верхнего уровня. Имена разрешаются в пространстве имён верхнего уровня путём поиска в глобальном пространстве имён, т. е. в пространстве имён модуля, содержащего блок кода, и в пространстве имён builtins, пространстве имён модуля builtins. Глобальное пространство имён ищется в первую очередь. Если имена не найдены там, ищется пространство имён builtins. Если имена также не найдены в пространстве имён 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__ объектов, определённых в области. Вместо этого,
__qualname__таких объектов как если бы объект был определён во внешней области.
Добавлен в версии 3.12: Области аннотаций были введены в Python 3.12 в рамках PEP 695.
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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/reference/executionmodel.html