Spec-Zone.ru › Python 3.13

Модель выполнения

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 не имеет объявлений и позволяет операциям связывания имён происходить где угодно внутри блока кода. Локальные переменные блока кода можно определить, просканировав весь текст блока на предмет операций связывания имён. См. статью в FAQ об 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.

Примечания

[1]

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

© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/reference/executionmodel.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API