Spec-Zone.ru › Python 3.11

Модель данных

3.1. Объекты, значения и типы

Объекты — это абстракция данных в Python. Все данные в программе на Python представлены объектами или отношениями между объектами. (В некотором смысле, в соответствии с моделью фон Неймана для «компьютера с хранимой программой», код также представлен объектами.)

У каждого объекта есть идентификатор, тип и значение. Идентификатор объекта не меняется после его создания; можно считать его адресом объекта в памяти. Оператор is сравнивает идентификаторы двух объектов; функция id() возвращает целое число, представляющее его идентификатор.

Особенность реализации CPython: В CPython id(x) — это адрес в памяти, по которому хранится x.

Тип объекта определяет поддерживаемые им операции (например, «есть ли у него длина?»), а также допустимые значения объектов этого типа. Функция type() возвращает тип объекта (который сам является объектом). Как и идентификатор, тип объекта также неизменяем. [1]

Значение некоторых объектов может меняться. Объекты, значение которых может меняться, называют изменяемыми; объекты, значение которых нельзя изменить после создания, называют неизменяемыми. (Значение неизменяемого объекта-контейнера, содержащего ссылку на изменяемый объект, может измениться при изменении значения последнего; однако контейнер по-прежнему считается неизменяемым, поскольку набор содержащихся в нём объектов изменить нельзя. Таким образом, неизменяемость — это не совсем то же самое, что неизменяемое значение; понятие несколько тоньше.) Изменяемость объекта определяется его типом: например, числа, строки и кортежи неизменяемы, а словари и списки изменяемы.

Объекты никогда не уничтожаются явно; однако, когда они становятся недостижимыми, они могут быть собраны сборщиком мусора. Реализация может отложить сборку мусора или вовсе её не выполнять — качество реализации определяется тем, как именно реализована сборка мусора, при условии, что не удаляются объекты, которые всё ещё достижимы.

Особенность реализации CPython: В настоящее время CPython использует подсчёт ссылок с (необязательным) отложенным обнаружением циклических ссылок на мусор. Эта схема собирает большинство объектов, как только они становятся недостижимыми, но не гарантирует сборку мусора, содержащего циклические ссылки. Сведения об управлении сборкой циклического мусора см. в документации модуля gc. Другие реализации работают иначе, и CPython может измениться. Не полагайтесь на немедленное уничтожение объектов после того, как они станут недостижимыми (поэтому файлы всегда следует закрывать явно).

Обратите внимание, что средства трассировки или отладки реализации могут сохранять объекты, которые обычно подлежали бы сборке. Также учтите, что перехват исключения с помощью инструкции try…except может сохранять объекты.

Некоторые объекты содержат ссылки на «внешние» ресурсы, например открытые файлы или окна. Предполагается, что эти ресурсы освобождаются при сборке объекта сборщиком мусора, но поскольку сборка мусора не гарантирована, такие объекты также предоставляют явный способ освободить внешний ресурс, обычно метод close(). Настоятельно рекомендуется явно закрывать такие объекты. Инструкции try…finally и with предоставляют удобные способы сделать это.

Некоторые объекты содержат ссылки на другие объекты; их называют контейнерами. Примеры контейнеров — кортежи, списки и словари. Ссылки являются частью значения контейнера. В большинстве случаев, говоря о значении контейнера, мы имеем в виду значения, а не идентификаторы содержащихся объектов; однако, говоря об изменяемости контейнера, мы подразумеваем только идентификаторы непосредственно содержащихся в нём объектов. Поэтому если неизменяемый контейнер (например, кортеж) содержит ссылку на изменяемый объект, его значение меняется при изменении этого изменяемого объекта.

Типы влияют почти на все аспекты поведения объектов. В некотором смысле они влияют даже на важность идентификатора объекта: для неизменяемых типов операции, вычисляющие новые значения, могут фактически возвращать ссылку на любой существующий объект того же типа и со значением, тогда как для изменяемых объектов это недопустимо. Например, после a = 1; b = 1, a и b могут ссылаться или не ссылаться на один и тот же объект со значением один — это зависит от реализации; однако после c = []; d = [], c и d гарантированно будут ссылаться на два разных, уникальных, вновь созданных пустых списка. (Обратите внимание, что c = d = [] присваивает один и тот же объект и c, и d.)

3.2. Стандартная иерархия типов

Ниже перечислены типы, встроенные в Python. Модули расширения (написанные на C, Java или других языках — в зависимости от реализации) могут определять дополнительные типы. В будущих версиях Python в иерархию типов могут добавляться новые типы (например, рациональные числа, эффективно хранящиеся массивы целых чисел и т. д.), хотя такие дополнения часто предоставляются вместо этого через стандартную библиотеку.

Некоторые описания типов ниже содержат абзац со списком «специальных атрибутов». Эти атрибуты предоставляют доступ к реализации и не предназначены для общего использования. Их определение может измениться в будущем.

3.2.1. None

У этого типа есть единственное значение. Существует только один объект с этим значением. Доступ к этому объекту осуществляется через встроенное имя None. Во многих ситуациях оно используется для обозначения отсутствия значения; например, его возвращают функции, которые явно ничего не возвращают. Его логическое значение — ложь.

3.2.2. NotImplemented

У этого типа есть единственное значение. Существует только один объект с этим значением. Доступ к этому объекту осуществляется через встроенное имя NotImplemented. Числовые методы и методы расширенного сравнения должны возвращать это значение, если они не реализуют операцию для переданных операндов. (Затем интерпретатор попробует выполнить отражённую операцию или применит другой вариант обработки — в зависимости от оператора.) Его не следует вычислять в логическом контексте.

Подробнее см. Реализация арифметических операций.

Изменено в версии 3.9: Вычисление NotImplemented в логическом контексте считается устаревшим. Сейчас оно вычисляется как истина, но при этом выдаётся предупреждение DeprecationWarning. В будущей версии Python будет вызвано исключение TypeError.

3.2.3. Ellipsis

У этого типа есть единственное значение. Существует только один объект с этим значением. Доступ к этому объекту осуществляется через литерал ... или встроенное имя Ellipsis. Его логическое значение — истина.

3.2.4. numbers.Number

Числа создаются числовыми литералами и возвращаются в качестве результатов арифметическими операторами и встроенными арифметическими функциями. Числовые объекты неизменяемы; после создания их значение никогда не меняется. Числа Python, разумеется, тесно связаны с математическими числами, но ограничены особенностями числового представления в компьютерах.

Строковые представления числовых классов, вычисляемые с помощью __repr__() и __str__(), обладают следующими свойствами:

  • Это допустимые числовые литералы, которые при передаче конструктору соответствующего класса создают объект со значением исходного числа.
  • Если возможно, представление использует основание 10.
  • Начальные нули не отображаются, за исключением, возможно, одного нуля перед десятичной точкой.
  • Конечные нули не отображаются, за исключением, возможно, одного нуля после десятичной точки.
  • Знак отображается только для отрицательных чисел.

Python различает целые числа, числа с плавающей точкой и комплексные числа:

3.2.4.1. numbers.Integral

Они представляют элементы математического множества целых чисел (положительных и отрицательных).

Примечание

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

Существует два типа целых чисел:

Integers (int)

Они представляют числа неограниченного диапазона, ограниченного только доступной (виртуальной) памятью. Для операций сдвига и маскирования предполагается двоичное представление, а отрицательные числа представляются в варианте дополнительного кода, создающем иллюзию бесконечной строки знаковых битов, продолжающейся влево.

Booleans (bool)

Они представляют логические значения False и True. Объекты, представляющие значения False и True, — единственные логические объекты. Логический тип является подтипом целочисленного типа, и логические значения почти во всех контекстах ведут себя соответственно как значения 0 и 1. Исключение составляют случаи преобразования в строку: тогда возвращаются строки "False" и "True" соответственно.

3.2.4.2. numbers.Real (float)

Они представляют числа с плавающей точкой двойной точности на уровне машины. Допустимый диапазон и обработка переполнения зависят от архитектуры базовой машины (и реализации на C или Java). Python не поддерживает числа с плавающей точкой одинарной точности: экономия процессорных ресурсов и памяти, обычно являющаяся причиной их использования, незначительна по сравнению с накладными расходами на использование объектов в Python, поэтому усложнять язык двумя видами чисел с плавающей точкой нет смысла.

3.2.4.3. numbers.Complex (complex)

Они представляют комплексные числа в виде пары чисел с плавающей точкой двойной точности на уровне машины. К ним применимы те же оговорки, что и к числам с плавающей точкой. Действительную и мнимую части комплексного числа z можно получить с помощью атрибутов только для чтения z.real и z.imag.

3.2.5. Последовательности

Они представляют собой конечные упорядоченные наборы, индексируемые неотрицательными числами. Встроенная функция len() возвращает количество элементов последовательности. Если длина последовательности равна n, множество индексов содержит числа 0, 1, …, n-1. Элемент i последовательности a выбирается с помощью a[i]. Некоторые последовательности, в том числе встроенные, интерпретируют отрицательные индексы, прибавляя к ним длину последовательности. Например, a[-2] равно a[n-2] — предпоследнему элементу последовательности a длины n.

Последовательности также поддерживают срезы: a[i:j] выбирает все элементы с индексом k, для которого i <= k < j. При использовании в качестве выражения срез представляет собой последовательность того же типа. Приведённое выше замечание об отрицательных индексах также относится к отрицательным позициям среза.

Некоторые последовательности также поддерживают «расширенные срезы» с третьим параметром — «шагом»: a[i:j:k] выбирает все элементы a с индексом x, для которого x = i + n*k, n >= 0 и i <= x < j.

Последовательности различаются по изменяемости:

3.2.5.1. Неизменяемые последовательности

Объект неизменяемого типа последовательности нельзя изменить после его создания. (Если объект содержит ссылки на другие объекты, эти объекты могут быть изменяемыми и могут изменяться; однако набор объектов, на которые непосредственно ссылается неизменяемый объект, изменить нельзя.)

К неизменяемым последовательностям относятся следующие типы:

Строки

Строка — это последовательность значений, представляющих кодовые точки Unicode. В строке можно представить все кодовые точки диапазона U+0000 - U+10FFFF. В Python нет типа char; вместо этого каждая кодовая точка строки представлена строковым объектом длины 1. Встроенная функция ord() преобразует кодовую точку из строкового представления в целое число диапазона 0 - 10FFFF; chr() преобразует целое число диапазона 0 - 10FFFF в соответствующий строковый объект длины 1. С помощью str.encode() можно преобразовать str в bytes, используя заданную кодировку текста, а с помощью bytes.decode() можно выполнить обратное преобразование.

Кортежи

Элементы кортежа могут быть произвольными объектами Python. Кортежи из двух или более элементов создаются списками выражений, разделённых запятыми. Кортеж из одного элемента («одноэлементный кортеж») можно создать, добавив запятую после выражения (само по себе выражение не создаёт кортеж, поскольку круглые скобки должны использоваться для группировки выражений). Пустой кортеж можно создать пустой парой круглых скобок.

Байты

Объект bytes — это неизменяемый массив. Его элементы — 8-битные байты, представленные целыми числами диапазона 0 <= x < 256. Для создания объектов bytes можно использовать литералы bytes (например, b'abc') и конструктор bytes(). Кроме того, объекты bytes можно декодировать в строки с помощью метода decode().

3.2.5.2. Изменяемые последовательности

Изменяемые последовательности можно менять после их создания. Обозначения индексации и срезов можно использовать в качестве цели присваивания и инструкций del (удаления).

Примечание

Модули collections и array предоставляют дополнительные примеры типов изменяемых последовательностей.

В настоящее время существует два встроенных типа изменяемых последовательностей:

Списки

Элементы списка могут быть произвольными объектами Python. Списки создаются путём помещения списка выражений, разделённых запятыми, в квадратные скобки. (Обратите внимание, что для создания списков длины 0 или 1 не нужны особые случаи.)

Массивы байтов

Объект bytearray — это изменяемый массив. Такие объекты создаются встроенным конструктором bytearray(). Помимо изменяемости (и, следовательно, нехешируемости), массивы байтов предоставляют тот же интерфейс и функциональность, что и неизменяемые объекты bytes.

3.2.6. Типы множеств

Они представляют собой неупорядоченные конечные множества уникальных неизменяемых объектов. Поэтому индексировать их с помощью индекса нельзя. Однако по ним можно выполнять итерацию, а встроенная функция len() возвращает количество элементов множества. Множества часто используют для быстрой проверки принадлежности, удаления повторяющихся элементов из последовательности и вычисления математических операций, таких как пересечение, объединение, разность и симметрическая разность.

Для элементов множеств действуют те же правила неизменяемости, что и для ключей словаря. Обратите внимание, что числовые типы подчиняются обычным правилам сравнения чисел: если два числа равны при сравнении (например, 1 и 1.0), множество может содержать только одно из них.

В настоящее время существует два встроенных типа множеств:

Множества

Они представляют собой изменяемые множества. Такие объекты создаются встроенным конструктором set(), а затем их можно изменять с помощью нескольких методов, например add().

Неизменяемые множества

Они представляют собой неизменяемые множества. Такие объекты создаются встроенным конструктором frozenset(). Поскольку frozenset неизменяем и хешируем, его можно использовать как элемент другого множества или как ключ словаря.

3.2.7. Отображения

Они представляют собой конечные наборы объектов, индексируемые произвольными множествами индексов. Обозначение индексации a[k] выбирает из отображения a элемент с индексом k; его можно использовать в выражениях и в качестве цели присваивания или инструкции del. Встроенная функция len() возвращает количество элементов отображения.

В настоящее время существует только один встроенный тип отображения:

3.2.7.1. Словари

Они представляют собой конечные наборы объектов, индексируемые почти произвольными значениями. В качестве ключей нельзя использовать только значения, содержащие списки, словари или другие изменяемые типы, сравниваемые по значению, а не по идентификатору объекта. Причина в том, что для эффективной реализации словарей хеш-значение ключа должно оставаться неизменным. Числовые типы, используемые в качестве ключей, подчиняются обычным правилам сравнения чисел: если два числа равны при сравнении (например, 1 и 1.0), их можно взаимозаменяемо использовать для доступа к одной и той же записи словаря.

Словари сохраняют порядок вставки, то есть ключи будут возвращаться в том же порядке, в котором они последовательно добавлялись в словарь. Замена существующего ключа не меняет порядок, однако удаление ключа и его повторная вставка переместит его в конец, а не оставит на прежнем месте.

Словари изменяемы; их можно создавать с помощью обозначения {...} (см. раздел Литералы словарей).

Модули расширения dbm.ndbm и dbm.gnu предоставляют дополнительные примеры типов отображений, как и модуль collections.

Изменено в версии 3.7: В версиях Python до 3.6 словари не сохраняли порядок вставки. В CPython 3.6 порядок вставки сохранялся, но в то время это считалось особенностью реализации, а не гарантией языка.

3.2.8. Вызываемые типы

Это типы, к которым можно применить операцию вызова функции (см. раздел Вызовы):

3.2.8.1. Функции, определённые пользователем

Объект функции, определённой пользователем, создаётся определением функции (см. раздел Определения функций). При вызове ему следует передавать список аргументов, содержащий столько же элементов, сколько формальных параметров в списке параметров функции.

3.2.8.1.1. Специальные атрибуты только для чтения

Атрибут

Значение

function.__globals__

Ссылка на dictionary, содержащий глобальные переменные функции, — глобальное пространство имён модуля, в котором была определена функция.

function.__closure__

None или tuple ячеек, содержащих привязки для свободных переменных функции.

У объекта-ячейки есть атрибут cell_contents. Его можно использовать для получения и установки значения ячейки.

3.2.8.1.2. Специальные атрибуты для записи

Большинство этих атрибутов проверяют тип присваиваемого значения:

Атрибут

Значение

function.__doc__

Строка документации функции или None, если она отсутствует. Не наследуется подклассами.

function.__name__

Имя функции. См. также: __name__ attributes.

function.__qualname__

Полное имя функции. См. также: __qualname__ attributes.

Добавлено в версии 3.3.

function.__module__

Имя модуля, в котором была определена функция, или None, если оно недоступно.

function.__defaults__

tuple, содержащий значения по умолчанию для тех параметров, для которых они заданы, или None, если ни для одного параметра значение по умолчанию не задано.

function.__code__

Объект кода, представляющий скомпилированное тело функции.

function.__dict__

Пространство имён для произвольных атрибутов функции. См. также: __dict__ attributes.

function.__annotations__

dictionary, содержащий аннотации параметров. Ключи словаря — имена параметров, а 'return' — аннотация возвращаемого значения, если она указана. См. также: Рекомендации по работе с аннотациями.

function.__kwdefaults__

dictionary, содержащий значения по умолчанию для параметров, доступных только по ключевому слову.

Объекты функций также поддерживают получение и установку произвольных атрибутов, которые можно использовать, например, для добавления метаданных к функциям. Для получения и установки таких атрибутов используется обычная точечная нотация атрибутов.

Особенность реализации CPython: Текущая реализация CPython поддерживает атрибуты функций только для функций, определённых пользователем. Поддержка атрибутов функций у встроенных функций может появиться в будущем.

Дополнительную информацию об определении функции можно получить из её объекта кода (доступного через атрибут __code__).

3.2.8.2. Методы экземпляров

Объект метода экземпляра объединяет класс, экземпляр класса и любой вызываемый объект (обычно функцию, определённую пользователем).

Специальные атрибуты только для чтения:

method.__self__

Ссылка на экземпляр класса, к которому привязан метод (привязан)

method.__func__

Ссылка на исходный объект функции

method.__doc__

Документация метода (та же, что и у method.__func__.__doc__). Объект string, если у исходной функции была строка документации, иначе None.

method.__name__

Имя метода (то же, что и method.__func__.__name__)

method.__module__

Имя модуля, в котором был определён метод, или None, если оно недоступно.

Методы также поддерживают доступ (но не изменение) к произвольным атрибутам функции, лежащей в основе метода, — объекта функции.

Объекты методов, определённых пользователем, могут создаваться при получении атрибута класса (возможно, через экземпляр этого класса), если этот атрибут является объектом функции, определённой пользователем, или объектом classmethod.

Когда объект метода экземпляра создаётся при получении функции, определённой пользователем, из класса через один из его экземпляров, его атрибут __self__ содержит экземпляр, и такой объект метода называется привязанным. Атрибут __func__ нового метода содержит исходный объект функции.

Когда объект метода экземпляра создаётся при получении объекта classmethod из класса или экземпляра, его атрибут __self__ содержит сам класс, а атрибут __func__ — объект функции, лежащий в основе метода класса.

При вызове объекта метода экземпляра вызывается лежащая в его основе функция (__func__), причём экземпляр класса (__self__) вставляется в начало списка аргументов. Например, если C — класс, содержащий определение функции f(), а x — экземпляр C, то вызов x.f(1) эквивалентен вызову C.f(x, 1).

Если объект метода экземпляра получен из объекта classmethod, «экземпляром класса», хранящимся в __self__, будет сам класс, поэтому вызов x.f(1) или C.f(1) эквивалентен вызову f(C,1), где f — лежащая в основе функция.

Обратите внимание: преобразование объекта функции в объект метода экземпляра происходит каждый раз при получении атрибута экземпляра. В некоторых случаях полезно присвоить атрибут локальной переменной и вызывать эту переменную. Также обратите внимание, что это преобразование происходит только для функций, определённых пользователем; другие вызываемые объекты (и все невызываемые объекты) возвращаются без преобразования. Важно также отметить, что функции, определённые пользователем и являющиеся атрибутами экземпляра класса, не преобразуются в привязанные методы; это происходит только тогда, когда функция является атрибутом класса.

3.2.8.3. Функции-генераторы

Функция или метод, использующие оператор yield (см. раздел Оператор yield), называются функцией-генератором. При вызове такая функция всегда возвращает объект итератора, который можно использовать для выполнения тела функции: вызов метода iterator.__next__() итератора приведёт к выполнению функции до тех пор, пока она не выдаст значение с помощью оператора yield. Когда функция выполнит оператор return или завершится, будет вызвано исключение StopIteration, и итератор достигнет конца последовательности возвращаемых значений.

3.2.8.4. Функции-корутины

Функция или метод, определённые с помощью async def, называются функцией-корутиной. При вызове такая функция возвращает объект корутины. Она может содержать выражения await, а также операторы async with и async for. См. также раздел Объекты-корутины.

3.2.8.5. Асинхронные функции-генераторы

Функция или метод, определённые с помощью async def и использующие оператор yield, называются асинхронной функцией-генератором. При вызове такая функция возвращает объект асинхронного итератора, который можно использовать в операторе async for для выполнения тела функции.

Вызов метода aiterator.__anext__ асинхронного итератора вернёт объект ожидаемого объекта; при ожидании он будет выполняться до тех пор, пока не выдаст значение с помощью выражения yield. Когда функция выполнит пустой оператор return или завершится, будет вызвано исключение StopAsyncIteration, и асинхронный итератор достигнет конца последовательности выдаваемых значений.

3.2.8.6. Встроенные функции

Объект встроенной функции — это обёртка вокруг функции на языке C. Примеры встроенных функций: len() и math.sin() (math — стандартный встроенный модуль). Количество и тип аргументов определяются функцией на языке C. Специальные атрибуты только для чтения:

  • __doc__ — строка документации функции или None, если она отсутствует. См. function.__doc__.
  • __name__ — имя функции. См. function.__name__.
  • __self__ имеет значение None (но см. следующий пункт).
  • __module__ — имя модуля, в котором была определена функция, или None, если оно недоступно. См. function.__module__.

3.2.8.7. Встроенные методы

Это, по сути, другая форма встроенной функции, на этот раз содержащая объект, передаваемый функции на языке C как неявный дополнительный аргумент. Пример встроенного метода — alist.append(), если alist — объект списка. В этом случае специальный атрибут только для чтения __self__ ссылается на объект, обозначенный alist. (Семантика атрибута такая же, как у other instance methods.)

3.2.8.8. Классы

Классы являются вызываемыми объектами. Обычно они выступают в роли фабрик, создающих новые экземпляры самого класса, однако для типов классов, переопределяющих __new__(), возможны и другие варианты. Аргументы вызова передаются в __new__() и, в типичном случае, в __init__() для инициализации нового экземпляра.

3.2.8.9. Экземпляры классов

Экземпляры произвольных классов можно сделать вызываемыми, определив в их классе метод __call__().

3.2.9. Модули

Модули — основная организационная единица кода Python; они создаются системой импорта, вызываемой оператором import или вызовом таких функций, как importlib.import_module() и встроенная функция __import__(). Пространство имён объекта модуля реализовано объектом dictionary (это словарь, на который ссылается атрибут __globals__ функций, определённых в модуле). Обращения к атрибутам преобразуются в поиск в этом словаре: например, m.x эквивалентно m.__dict__["x"]. Объект модуля не содержит объект кода, использованный для его инициализации (поскольку после завершения инициализации он не нужен).

Присваивание атрибуту обновляет словарь пространства имён модуля: например, m.x = 1 эквивалентно m.__dict__["x"] = 1.

Предопределённые (доступные для записи) атрибуты:

__name__

Имя модуля.

__doc__

Строка документации модуля или None, если она отсутствует.

__file__

Путь к файлу, из которого был загружен модуль, если он был загружен из файла. Атрибут __file__ может отсутствовать у некоторых типов модулей, например у модулей на языке C, статически скомпонованных с интерпретатором. Для модулей расширений, динамически загруженных из разделяемой библиотеки, это путь к файлу разделяемой библиотеки.

__annotations__

Словарь, содержащий аннотации переменных, собранные во время выполнения тела модуля. Рекомендации по работе с __annotations__ см. в разделе Рекомендации по работе с аннотациями.

Специальный атрибут только для чтения: __dict__ — пространство имён модуля в виде объекта-словаря.

Особенность реализации CPython: Из-за особенностей очистки словарей модулей в CPython словарь модуля будет очищен, когда модуль выйдет из области видимости, даже если на словарь всё ещё существуют действующие ссылки. Чтобы избежать этого, скопируйте словарь или сохраните модуль, пока напрямую используете его словарь.

3.2.10. Пользовательские классы

Типы пользовательских классов обычно создаются определениями классов (см. раздел Определения классов). Пространство имён класса реализовано объектом-словарём. Обращения к атрибутам класса преобразуются в поиск в этом словаре: например, C.x преобразуется в C.__dict__["x"] (хотя существует ряд перехватчиков, позволяющих находить атрибуты и другими способами). Если имя атрибута там не найдено, поиск продолжается в базовых классах. Для поиска в базовых классах используется порядок разрешения методов C3, который корректно работает даже при наличии «ромбовидных» структур наследования с несколькими путями наследования к общему предку. Дополнительные сведения о MRO C3, используемом в Python, приведены в документации к выпуску 2.3 по адресу https://www.python.org/download/releases/2.3/mro/.

Если обращение к атрибуту класса (например, класса C) должно вернуть объект метода класса, оно преобразуется в объект метода экземпляра, атрибут __self__ которого равен C. Если оно должно вернуть объект staticmethod, то преобразование возвращает объект, обёрнутый объектом статического метода. О другом способе, которым атрибуты, полученные из класса, могут отличаться от атрибутов, фактически содержащихся в его __dict__, см. раздел Реализация дескрипторов.

Присваивание атрибутам класса обновляет словарь этого класса, но никогда не словарь базового класса.

Объект класса можно вызвать (см. выше), чтобы получить экземпляр класса (см. ниже).

Специальные атрибуты:

__name__

Имя класса.

__module__

Имя модуля, в котором был определён класс.

__dict__

Словарь, содержащий пространство имён класса.

__bases__

Кортеж, содержащий базовые классы в том порядке, в котором они указаны в списке базовых классов.

__doc__

Строка документации класса или None, если она не определена.

__annotations__

Словарь, содержащий аннотации переменных, собранные во время выполнения тела класса. Рекомендации по работе с __annotations__ см. в разделе Рекомендации по работе с аннотациями.

3.2.11. Экземпляры классов

Экземпляр класса создаётся вызовом объекта класса (см. выше). Пространство имён экземпляра класса реализовано словарём, в котором в первую очередь выполняется поиск при обращении к атрибутам. Если атрибут там не найден, а в классе экземпляра есть атрибут с таким именем, поиск продолжается среди атрибутов класса. Если найденный атрибут класса является объектом функции, определённой пользователем, он преобразуется в объект метода экземпляра, атрибут __self__ которого содержит экземпляр. Объекты статических методов и методов класса также преобразуются; см. раздел «Классы» выше. О другом способе, которым атрибуты класса, полученные через его экземпляры, могут отличаться от объектов, фактически хранящихся в __dict__ класса, см. раздел Реализация дескрипторов. Если атрибут класса не найден, а у класса объекта есть метод __getattr__(), он вызывается для выполнения поиска.

Присваивание атрибутов и их удаление обновляют словарь экземпляра, но никогда не словарь класса. Если у класса есть метод __setattr__() или __delattr__(), он вызывается вместо непосредственного обновления словаря экземпляра.

Экземпляры классов могут вести себя как числа, последовательности или отображения, если в них определены методы с определёнными специальными именами. См. раздел Специальные имена методов.

Специальные атрибуты: __dict__ — словарь атрибутов; __class__ — класс экземпляра.

3.2.12. Объекты ввода-вывода (также называемые файловыми объектами)

Файловый объект представляет открытый файл. Для создания файловых объектов доступны различные способы: встроенная функция open(), а также os.popen(), os.fdopen() и метод makefile() объектов сокетов (а также, возможно, другие функции или методы, предоставляемые модулями расширений).

Объекты sys.stdin, sys.stdout и sys.stderr инициализируются файловыми объектами, соответствующими стандартным потокам ввода, вывода и ошибок интерпретатора; все они открыты в текстовом режиме и поэтому соответствуют интерфейсу, определённому абстрактным классом io.TextIOBase.

3.2.13. Внутренние типы

Некоторые типы, используемые интерпретатором внутри, доступны пользователю. Их определения могут измениться в будущих версиях интерпретатора, но здесь они упоминаются для полноты картины.

3.2.13.1. Объекты кода

Объекты кода представляют скомпилированный в байт-код исполняемый код Python, или байт-код. Разница между объектом кода и объектом функции заключается в том, что объект функции содержит явную ссылку на глобальные переменные функции (модуль, в котором она была определена), тогда как объект кода не содержит контекста; значения аргументов по умолчанию также хранятся в объекте функции, а не в объекте кода (поскольку они представляют собой значения, вычисляемые во время выполнения). В отличие от объектов функций, объекты кода неизменяемы и не содержат ссылок (прямых или косвенных) на изменяемые объекты.

3.2.13.1.1. Специальные атрибуты только для чтения
codeobject.co_name

Имя функции

codeobject.co_qualname

Полное имя функции

Добавлено в версии 3.11.

codeobject.co_argcount

Общее число позиционных параметров функции (включая параметры, допускающие передачу только по позиции, и параметры со значениями по умолчанию)

codeobject.co_posonlyargcount

Число позиционных параметров функции, допускающих передачу только по позиции (включая аргументы со значениями по умолчанию)

codeobject.co_kwonlyargcount

Число именованных параметров функции, допускающих передачу только по имени (включая аргументы со значениями по умолчанию)

codeobject.co_nlocals

Число локальных переменных, используемых функцией (включая параметры)

codeobject.co_varnames

tuple, содержащий имена локальных переменных функции (начиная с имён параметров)

codeobject.co_cellvars

tuple, содержащий имена локальных переменных, на которые ссылаются вложенные функции внутри этой функции

codeobject.co_freevars

tuple, содержащий имена свободных переменных функции

codeobject.co_code

Строка, представляющая последовательность инструкций байт-кода функции

codeobject.co_consts

tuple, содержащий литералы, используемые байт-кодом функции

codeobject.co_names

tuple, содержащий имена, используемые байт-кодом функции

codeobject.co_filename

Имя файла, из которого был скомпилирован код

codeobject.co_firstlineno

Номер первой строки функции

codeobject.co_lnotab

Строка, кодирующая соответствие смещений байт-кода номерам строк. Подробности см. в исходном коде интерпретатора.

codeobject.co_stacksize

Требуемый размер стека для объекта кода

codeobject.co_flags

integer, кодирующее набор флагов интерпретатора.

Для co_flags определены следующие биты флагов: бит 0x04 установлен, если функция использует синтаксис *arguments для приёма произвольного числа позиционных аргументов; бит 0x08 установлен, если функция использует синтаксис **keywords для приёма произвольного числа именованных аргументов; бит 0x20 установлен, если функция является генератором. Подробное описание семантики каждого из возможных флагов см. в разделе Битовые флаги объектов кода.

Объявления будущих возможностей (from __future__ import division) также используют биты в co_flags, чтобы указать, был ли объект кода скомпилирован с включённой определённой возможностью: бит 0x2000 установлен, если функция была скомпилирована с включённым делением из будущих версий; биты 0x10 и 0x1000 использовались в более ранних версиях Python.

Другие биты в co_flags зарезервированы для внутреннего использования.

Если объект кода представляет функцию, первый элемент в co_consts — это строка документации функции или None, если она не определена.

3.2.13.1.2. Методы объектов кода
codeobject.co_positions()

Возвращает итерируемый объект с позициями в исходном коде для каждой инструкции байт-кода в объекте кода.

Итератор возвращает tuple, содержащие (start_line, end_line, start_column, end_column). Кортеж с индексом i соответствует позиции исходного кода, из которой была скомпилирована кодовая единица с индексом i. Информация о столбцах задаётся смещениями в байтах utf-8 с индексацией от нуля в указанной строке исходного кода.

Эта информация о позициях может отсутствовать. Ниже приведён неполный список случаев, когда это может произойти:

  • Запуск интерпретатора с параметром -X no_debug_ranges.
  • Загрузка файла pyc, скомпилированного с использованием параметра -X no_debug_ranges.
  • Кортежи позиций, соответствующие искусственным инструкциям.
  • Номера строк и столбцов, которые невозможно представить из-за ограничений реализации.

В таких случаях некоторые или все элементы кортежа могут иметь значение None.

Добавлено в версии 3.11.

Примечание

Для этой возможности требуется хранить позиции столбцов в объектах кода, что может немного увеличить объём дискового пространства, занимаемого скомпилированными файлами Python, или объём памяти, используемой интерпретатором. Чтобы не сохранять дополнительную информацию и/или отключить вывод дополнительных сведений в трассировке стека, можно использовать флаг командной строки -X no_debug_ranges или переменную окружения PYTHONNODEBUGRANGES.

codeobject.co_lines()

Возвращает итератор, выдающий информацию о последовательных диапазонах байт-кода. Каждый элемент представляет собой кортеж (start, end, lineno) tuple:

  • start (значение типа int) — включительное смещение начала диапазона байт-кода
  • end (значение типа int) — исключительное смещение конца диапазона байт-кода
  • lineno — значение типа int, представляющее номер строки для диапазона байт-кода, или None, если у байт-кода в указанном диапазоне нет номера строки

Выдаваемые элементы обладают следующими свойствами:

  • Первый выданный диапазон будет иметь start, равный 0.
  • Диапазоны (start, end) будут неубывающими и последовательными. То есть для любой пары tuple значение start второго будет равно значению end первого.
  • Диапазоны не будут обратными: end >= start для всех троек.
  • Последний выданный tuple будет иметь end, равный размеру байт-кода.

Допускаются диапазоны нулевой ширины, где start == end. Диапазоны нулевой ширины используются для строк, присутствующих в исходном коде, но удалённых компилятором байт-кода.

Добавлено в версии 3.10.

См. также

PEP 626 — Точные номера строк для отладки и других инструментов.

PEP, в котором был представлен метод co_lines().

codeobject.replace(**kwargs)

Возвращает копию объекта кода с новыми значениями указанных полей.

Добавлено в версии 3.8.

3.2.13.2. Объекты кадров

Объекты кадров представляют кадры выполнения. Они могут встречаться в объектах трассировки стека, а также передаются зарегистрированным функциям трассировки.

3.2.13.2.1. Специальные атрибуты только для чтения
frame.f_back

Указывает на предыдущий кадр стека (в направлении вызывающего кода) или на None, если это нижний кадр стека

frame.f_code

Объект кода, выполняемый в этом кадре. Обращение к этому атрибуту вызывает событие аудита object.__getattr__ с аргументами obj и "f_code".

frame.f_locals

Словарь, используемый кадром для поиска локальных переменных

frame.f_globals

Словарь, используемый кадром для поиска глобальных переменных

frame.f_builtins

Словарь, используемый кадром для поиска встроенных (внутренних) имён

frame.f_lasti

«Точная инструкция» объекта кадра (это индекс в строке байт-кода объекта кода)

3.2.13.2.2. Специальные атрибуты для чтения и записи
frame.f_trace

Если значение не равно None, это функция, вызываемая при различных событиях во время выполнения кода (она используется отладчиками). Обычно событие возникает для каждой новой строки исходного кода (см. f_trace_lines).

frame.f_trace_lines

Установите для этого атрибута значение False, чтобы отключить вызов события трассировки для каждой строки исходного кода.

frame.f_trace_opcodes

Установите для этого атрибута значение True, чтобы разрешить запрос событий для каждой операции с байт-кодом. Обратите внимание, что это может привести к неопределённому поведению интерпретатора, если исключения, вызванные функцией трассировки, распространятся до отслеживаемой функции.

frame.f_lineno

Текущий номер строки кадра. Запись в этот атрибут из функции трассировки приводит к переходу на указанную строку (только для самого нижнего кадра). Отладчик может реализовать команду перехода (также называемую «Установить следующую инструкцию»), записывая значение в этот атрибут.

3.2.13.2.3. Методы объектов кадров

Объекты кадров поддерживают один метод:

frame.clear()

Этот метод удаляет все ссылки кадра на локальные переменные. Кроме того, если кадр принадлежал генератору, генератор завершается. Это помогает разрывать циклы ссылок с участием объектов кадров (например, при перехвате исключения и сохранении его трассировки стека для последующего использования).

Если кадр в данный момент выполняется, возникает исключение RuntimeError.

Добавлено в версии 3.4.

3.2.13.3. Объекты трассировки стека

Объекты трассировки стека представляют трассировку стека исключения. Объект трассировки стека неявно создаётся при возникновении исключения, а также может быть явно создан вызовом types.TracebackType.

Изменено в версии 3.7: Теперь объекты трассировки стека можно явно создавать из кода Python.

При неявном создании трассировок стека, когда поиск обработчика исключения разматывает стек выполнения, на каждом разматываемом уровне перед текущей трассировкой стека вставляется объект трассировки стека. При входе в обработчик исключения трассировка стека становится доступна программе. (См. раздел Инструкция try.) Она доступна как третий элемент кортежа, возвращаемого sys.exc_info(), и как атрибут __traceback__ перехваченного исключения.

Если в программе нет подходящего обработчика, трассировка стека записывается (в удобочитаемом формате) в поток стандартного вывода ошибок; если интерпретатор работает в интерактивном режиме, трассировка также становится доступна пользователю как sys.last_traceback.

При явном создании трассировки стека создатель трассировки определяет, как должны быть связаны атрибуты tb_next, чтобы сформировать полную трассировку стека.

Специальные атрибуты только для чтения:

traceback.tb_frame

Указывает на кадр выполнения текущего уровня.

Обращение к этому атрибуту вызывает событие аудита object.__getattr__ с аргументами obj и "tb_frame".

traceback.tb_lineno

Возвращает номер строки, в которой возникло исключение

traceback.tb_lasti

Указывает «точную инструкцию».

Номер строки и последняя инструкция в трассировке стека могут отличаться от номера строки соответствующего объекта кадра, если исключение возникло в инструкции try без подходящего блока except или с блоком finally.

traceback.tb_next

Специальный атрибут для чтения и записи tb_next указывает на следующий уровень трассировки стека (в направлении кадра, в котором возникло исключение) или на None, если следующего уровня нет.

Изменено в версии 3.7: Теперь этому атрибуту можно присваивать значение

3.2.13.4. Объекты срезов

Объекты срезов используются для представления срезов в методах __getitem__(). Они также создаются встроенной функцией slice().

Специальные атрибуты только для чтения: start — нижняя граница; stop — верхняя граница; step — шаг; значением каждого атрибута будет None, если он не указан. Эти атрибуты могут иметь любой тип.

Объекты срезов поддерживают один метод:

slice.indices(self, length)

Этот метод принимает один целочисленный аргумент length и вычисляет сведения о срезе, который описывал бы объект среза при применении к последовательности из length элементов. Метод возвращает кортеж из трёх целых чисел: соответственно, индексы start и stop, а также step, то есть шаг среза. Отсутствующие индексы и индексы за границами обрабатываются так же, как в обычных срезах.

3.2.13.5. Объекты статических методов

Объекты статических методов позволяют предотвратить преобразование объектов функций в объекты методов, описанное выше. Объект статического метода — это обёртка для любого другого объекта, обычно объекта метода, определённого пользователем. При получении объекта статического метода из класса или экземпляра класса фактически возвращается обёрнутый объект, который больше не подвергается преобразованиям. Объекты статических методов также являются вызываемыми. Объекты статических методов создаются встроенным конструктором staticmethod().

3.2.13.6. Объекты методов класса

Объект метода класса, как и объект статического метода, является обёрткой для другого объекта, изменяющей способ получения этого объекта из классов и экземпляров классов. Поведение объектов методов класса при таком получении описано выше в разделе «Методы экземпляров». Объекты методов класса создаются встроенным конструктором classmethod().

3.3. Специальные имена методов

Класс может реализовать определённые операции, вызываемые специальным синтаксисом (например, арифметические операции или индексирование и срезы), определяя методы со специальными именами. Так в Python реализована перегрузка операторов, позволяющая классам задавать собственное поведение для операторов языка. Например, если класс определяет метод с именем __getitem__(), а x является экземпляром этого класса, то x[i] примерно эквивалентно type(x).__getitem__(x, i). Если не указано иное, попытки выполнить операцию приводят к исключению, когда соответствующий метод не определён (обычно AttributeError или TypeError).

Установка специального метода в None означает, что соответствующая операция недоступна. Например, если класс устанавливает __iter__() в None, класс не является итерируемым, поэтому вызов iter() для его экземпляров приведёт к TypeError (без перехода к __getitem__()). [2]

При реализации класса, имитирующего любой встроенный тип, важно реализовывать такую имитацию лишь в той мере, в какой это имеет смысл для моделируемого объекта. Например, для некоторых последовательностей удобно получать отдельные элементы, но извлечение среза может быть бессмысленным. (Примером служит интерфейс NodeList в объектной модели документов W3C.)

3.3.1. Основная настройка

object.__new__(cls[, ...])

Вызывается для создания нового экземпляра класса cls. __new__() — статический метод (обрабатываемый особым образом, поэтому его не нужно объявлять как таковой), который принимает первым аргументом класс, экземпляр которого запрошен. Остальные аргументы — это аргументы, переданные выражению-конструктору объекта (вызову класса). Возвращаемым значением __new__() должен быть новый экземпляр объекта (обычно экземпляр cls).

Типичные реализации создают новый экземпляр класса, вызывая метод суперкласса __new__() с помощью super().__new__(cls[, ...]) и соответствующих аргументов, а затем при необходимости изменяют созданный экземпляр перед его возвратом.

Если __new__() вызывается при создании объекта и возвращает экземпляр cls, то будет вызван метод __init__() нового экземпляра, как в __init__(self[, ...]), где self — новый экземпляр, а остальные аргументы совпадают с переданными конструктору объекта.

Если __new__() не возвращает экземпляр cls, метод __init__() нового экземпляра вызван не будет.

__new__() предназначен главным образом для того, чтобы подклассы неизменяемых типов (таких как int, str или tuple) могли настраивать создание экземпляров. Его также часто переопределяют в пользовательских метаклассах, чтобы настраивать создание классов.

object.__init__(self[, ...])

Вызывается после создания экземпляра (методом __new__()), но до его возврата вызывающему коду. Аргументы совпадают с переданными выражению-конструктору класса. Если у базового класса есть метод __init__(), метод __init__() производного класса (если он есть) должен явно вызывать его, чтобы обеспечить правильную инициализацию части экземпляра, относящейся к базовому классу; например: super().__init__([args...]).

Поскольку __new__() и __init__() совместно участвуют в создании объектов (__new__() создаёт объект, а __init__() настраивает его), метод __init__() не может возвращать значение, отличное от None; в противном случае во время выполнения будет вызвано исключение TypeError.

object.__del__(self)

Вызывается, когда экземпляр собираются уничтожить. Этот метод также называют финализатором или (неправильно) деструктором. Если у базового класса есть метод __del__(), метод __del__() производного класса (если он есть) должен явно вызывать его, чтобы обеспечить правильное удаление части экземпляра, относящейся к базовому классу.

Метод __del__() может (хотя это и не рекомендуется!) отложить уничтожение экземпляра, создав на него новую ссылку. Это называется воскрешением объекта. Зависит от реализации, будет ли __del__() вызван повторно, когда воскрешённый объект собираются уничтожить; текущая реализация CPython вызывает его только один раз.

Не гарантируется, что методы __del__() будут вызваны для объектов, которые всё ещё существуют при завершении интерпретатора.

Примечание

del x не вызывает x.__del__() напрямую: первый уменьшает счётчик ссылок x на единицу, а второй вызывается только тогда, когда счётчик ссылок x достигает нуля.

Особенность реализации CPython: Цикл ссылок может помешать счётчику ссылок объекта достичь нуля. В этом случае цикл будет обнаружен и удалён позднее сборщиком циклического мусора. Частая причина возникновения циклов ссылок — исключение, перехваченное в локальной переменной. Локальные переменные кадра ссылаются на исключение, которое ссылается на собственную трассировку стека, а та, в свою очередь, ссылается на локальные переменные всех кадров, попавших в трассировку.

См. также

Документация модуля gc.

Предупреждение

Из-за ненадёжных условий, в которых вызываются методы __del__(), возникающие при их выполнении исключения игнорируются, а предупреждение выводится в sys.stderr. В частности:

  • __del__() может быть вызван во время выполнения произвольного кода, в том числе из произвольного потока. Если методу __del__() потребуется захватить блокировку или обратиться к другому блокирующему ресурсу, может возникнуть взаимная блокировка: этот ресурс уже может быть занят кодом, выполнение которого прервано ради вызова __del__().
  • __del__() может выполняться во время завершения работы интерпретатора. Поэтому глобальные переменные, к которым ему необходимо обратиться (включая переменные других модулей), могут быть уже удалены или установлены в None. Python гарантирует, что глобальные переменные, имена которых начинаются с одного символа подчёркивания, удаляются из модуля до удаления остальных глобальных переменных; если на такие переменные не ссылаются другие объекты, это может помочь обеспечить доступность импортированных модулей на момент вызова метода __del__().
object.__repr__(self)

Вызывается встроенной функцией repr() для вычисления «официального» строкового представления объекта. По возможности это должно быть корректное выражение Python, которое можно использовать для создания объекта с тем же значением (при наличии подходящего окружения). Если это невозможно, следует вернуть строку вида <...some useful description...>. Возвращаемое значение должно быть строковым объектом. Если класс определяет __repr__(), но не __str__(), то __repr__() также используется, когда требуется «неформальное» строковое представление экземпляров этого класса.

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

object.__str__(self)

Вызывается функцией str(object) и встроенными функциями format() и print() для вычисления «неформального» или удобного для печати строкового представления объекта. Возвращаемое значение должно быть объектом типа строка.

Этот метод отличается от object.__repr__() тем, что от __str__() не требуется возвращать корректное выражение Python: можно использовать более удобное или краткое представление.

Реализация по умолчанию, определённая встроенным типом object, вызывает object.__repr__().

object.__bytes__(self)

Вызывается функцией bytes для вычисления байтового строкового представления объекта. Метод должен возвращать объект bytes.

object.__format__(self, format_spec)

Вызывается встроенной функцией format(), а также, соответственно, при вычислении форматированных строковых литералов и метода str.format(), чтобы получить «форматированное» строковое представление объекта. Аргумент format_spec — это строка с описанием требуемых параметров форматирования. Интерпретация аргумента format_spec определяется типом, реализующим __format__(); однако большинство классов либо делегируют форматирование одному из встроенных типов, либо используют похожий синтаксис параметров форматирования.

Описание стандартного синтаксиса форматирования см. в разделе Мини-язык спецификации формата.

Возвращаемое значение должно быть строковым объектом.

Изменено в версии 3.4: Метод __format__ самого object вызывает исключение TypeError, если ему передана непустая строка.

Изменено в версии 3.7: Теперь object.__format__(x, '') эквивалентно str(x), а не format(str(x), '').

object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)

Это так называемые методы «расширенного сравнения». Соответствие между символами операторов и именами методов выглядит следующим образом: x<y вызывает x.__lt__(y), x<=y вызывает x.__le__(y), x==y вызывает x.__eq__(y), x!=y вызывает x.__ne__(y), x>y вызывает x.__gt__(y), а x>=y вызывает x.__ge__(y).

Метод расширенного сравнения может вернуть синглтон NotImplemented, если он не реализует операцию для заданной пары аргументов. По соглашению, при успешном сравнении возвращаются False и True. Однако эти методы могут возвращать любое значение, поэтому, если оператор сравнения используется в булевом контексте (например, в условии оператора if), Python вызовет для значения bool(), чтобы определить, является ли результат истинным или ложным.

По умолчанию object реализует __eq__() с помощью is, возвращая NotImplemented при ложном сравнении: True if x is y else NotImplemented. По умолчанию __ne__() делегирует выполнение __eq__() и инвертирует результат, если только он не равен NotImplemented. Между операторами сравнения и их реализациями по умолчанию нет других подразумеваемых связей; например, истинность (x<y or x==y) не означает истинность x<=y. Чтобы автоматически сгенерировать операции упорядочивания на основе одной базовой операции, см. functools.total_ordering().

В абзаце о __hash__() приведены важные замечания о создании хешируемых объектов с пользовательскими операциями сравнения, которые можно использовать в качестве ключей словаря.

Для этих методов не предусмотрены версии с переставленными аргументами (на случай, если левый аргумент не поддерживает операцию, а правый поддерживает); вместо этого __lt__() и __gt__() являются отражениями друг друга, __le__() и __ge__() также являются отражениями друг друга, а __eq__() и __ne__() отражают сами себя. Если операнды имеют разные типы, а тип правого операнда является прямым или косвенным подклассом типа левого операнда, приоритет имеет отражённый метод правого операнда; в противном случае приоритет имеет метод левого операнда. Виртуальное наследование от подкласса не учитывается.

Если ни один подходящий метод не возвращает значение, отличное от NotImplemented, операторы == и != переходят соответственно к is и is not.

object.__hash__(self)

Вызывается встроенной функцией hash() и при выполнении операций над элементами хешированных коллекций, включая set, frozenset и dict. Метод __hash__() должен возвращать целое число. Единственное обязательное свойство: объекты, которые сравниваются как равные, должны иметь одинаковое хеш-значение; рекомендуется объединять хеш-значения компонентов объекта, участвующих также в сравнении объектов, помещая их в кортеж и вычисляя хеш кортежа. Пример:

def __hash__(self):
    return hash((self.name, self.nick, self.color))

Примечание

hash() обрезает значение, возвращаемое пользовательским методом __hash__() объекта, до размера Py_ssize_t. Обычно это 8 байт в 64-разрядных сборках и 4 байта в 32-разрядных. Если метод __hash__() объекта должен обеспечивать совместимость сборок разной разрядности, обязательно проверьте ширину на всех поддерживаемых сборках. Это можно легко сделать с помощью python -c "import sys; print(sys.hash_info.width)".

Если класс не определяет метод __eq__(), ему также не следует определять операцию __hash__(); если класс определяет __eq__(), но не __hash__(), его экземпляры нельзя будет использовать в качестве элементов хешируемых коллекций. Если класс определяет изменяемые объекты и реализует метод __eq__(), ему не следует реализовывать __hash__(), поскольку для работы хешируемых коллекций требуется, чтобы хеш-значение ключа было неизменным (если хеш-значение объекта изменится, он окажется не в той хеш-корзине).

Пользовательские классы по умолчанию имеют методы __eq__() и __hash__(); с ними все объекты считаются неравными (кроме сравнения с самими собой), а x.__hash__() возвращает подходящее значение, благодаря которому из x == y следуют и x is y, и hash(x) == hash(y).

Для класса, переопределяющего __eq__() и не определяющего __hash__(), атрибут __hash__() неявно устанавливается в None. Если метод __hash__() класса равен None, при попытке получить хеш-значение его экземпляров программа вызовет соответствующее исключение TypeError; кроме того, при проверке с помощью isinstance(obj, collections.abc.Hashable) такие экземпляры будут правильно распознаны как нехешируемые.

Если классу, переопределяющему __eq__(), необходимо сохранить реализацию __hash__() родительского класса, об этом нужно явно сообщить интерпретатору, установив __hash__ = <ParentClass>.__hash__.

Если класс, не переопределяющий __eq__(), хочет отключить поддержку хеширования, ему следует включить __hash__ = None в определение класса. Класс, определяющий собственный __hash__(), который явно вызывает исключение TypeError, будет ошибочно распознан как хешируемый при вызове isinstance(obj, collections.abc.Hashable).

Примечание

По умолчанию значения __hash__() объектов str и bytes «солятся» непредсказуемым случайным значением. Хотя в рамках одного процесса Python они остаются неизменными, их нельзя предсказать между повторными запусками Python.

Это предназначено для защиты от отказа в обслуживании, вызванного специально подобранными входными данными, которые используют худшую производительность вставки в dict со сложностью O(n2). Подробности см. по адресу http://ocert.org/advisories/ocert-2011-003.html.

Изменение хеш-значений влияет на порядок перебора множеств. Python никогда не гарантировал этот порядок (и он обычно различается в 32-разрядных и 64-разрядных сборках).

См. также PYTHONHASHSEED.

Изменено в версии 3.3: Рандомизация хешей включена по умолчанию.

object.__bool__(self)

Вызывается для проверки истинности значения и реализации встроенной операции bool(); метод должен возвращать False или True. Если этот метод не определён, вызывается __len__(), если он определён; объект считается истинным, если результат ненулевой. Если класс не определяет ни __len__(), ни __bool__(), все его экземпляры считаются истинными.

3.3.2. Настройка доступа к атрибутам

Для настройки значения доступа к атрибутам (использования, присваивания или удаления x.name) экземпляров класса можно определить следующие методы.

object.__getattr__(self, name)

Вызывается, когда стандартный доступ к атрибуту завершается ошибкой AttributeError (либо __getattribute__() вызывает AttributeError, поскольку name не является атрибутом экземпляра или атрибутом в дереве классов для self; либо __get__() свойства name вызывает AttributeError). Этот метод должен вернуть вычисленное значение атрибута или вызвать исключение AttributeError.

Обратите внимание: если атрибут найден обычным способом, __getattr__() не вызывается. (Это намеренная асимметрия между __getattr__() и __setattr__().) Это сделано как из соображений эффективности, так и потому, что в противном случае у __getattr__() не было бы способа получить доступ к другим атрибутам экземпляра. Обратите внимание: по крайней мере для переменных экземпляра можно имитировать полный контроль, не помещая значения в словарь атрибутов экземпляра (а сохраняя их в другом объекте). О том, как получить полный контроль над доступом к атрибутам, см. описание метода __getattribute__() ниже.

object.__getattribute__(self, name)

Безусловно вызывается для реализации доступа к атрибутам экземпляров класса. Если класс также определяет __getattr__(), последний не будет вызван, если только __getattribute__() не вызовет его явно или не вызовет исключение AttributeError. Этот метод должен вернуть вычисленное значение атрибута или вызвать исключение AttributeError. Чтобы избежать бесконечной рекурсии в этом методе, его реализация всегда должна вызывать одноимённый метод базового класса для доступа к нужным атрибутам, например, object.__getattribute__(self, name).

Примечание

Этот метод всё же может обходиться при поиске специальных методов, если они неявно вызываются синтаксисом языка или встроенными функциями. См. раздел Поиск специальных методов.

При определённых обращениях к чувствительным атрибутам вызывает событие аудита object.__getattr__ с аргументами obj и name.

object.__setattr__(self, name, value)

Вызывается при попытке присвоить значение атрибуту. Вызывается вместо обычного механизма (то есть сохранения значения в словаре экземпляра). name — имя атрибута, value — присваиваемое ему значение.

Если __setattr__() нужно присвоить значение атрибуту экземпляра, следует вызвать одноимённый метод базового класса, например, object.__setattr__(self, name, value).

При определённых присваиваниях значений чувствительным атрибутам вызывает событие аудита object.__setattr__ с аргументами obj, name, value.

object.__delattr__(self, name)

Аналогичен __setattr__(), но вызывается при удалении атрибута, а не при присваивании. Этот метод следует реализовывать только в том случае, если del obj.name имеет смысл для объекта.

При определённых удалениях чувствительных атрибутов вызывает событие аудита object.__delattr__ с аргументами obj и name.

object.__dir__(self)

Вызывается, когда для объекта вызывается dir(). Должен быть возвращён итерируемый объект. dir() преобразует возвращённый итерируемый объект в список и сортирует его.

3.3.2.1. Настройка доступа к атрибутам модуля

Специальные имена __getattr__ и __dir__ также можно использовать для настройки доступа к атрибутам модуля. Функция __getattr__ на уровне модуля должна принимать один аргумент — имя атрибута — и возвращать вычисленное значение или вызывать исключение AttributeError. Если атрибут не найден в объекте модуля при обычном поиске, то есть с помощью object.__getattribute__(), перед вызовом исключения AttributeError в модуле __dict__ выполняется поиск __getattr__. Если функция найдена, она вызывается с именем атрибута, после чего возвращается результат.

Функция __dir__ должна принимать аргументы и возвращать итерируемый объект строк, представляющих имена, доступные в модуле. Если такая функция определена, она заменяет стандартный поиск dir() в модуле.

Для более точной настройки поведения модуля (установки атрибутов, свойств и т. д.) можно присвоить атрибуту __class__ объекта модуля подкласс types.ModuleType. Например:

import sys
from types import ModuleType

class VerboseModule(ModuleType):
    def __repr__(self):
        return f'Verbose {self.__name__}'

    def __setattr__(self, attr, value):
        print(f'Setting {attr}...')
        super().__setattr__(attr, value)

sys.modules[__name__].__class__ = VerboseModule

Примечание

Определение __getattr__ модуля и установка __class__ модуля влияют только на поиск, выполняемый с помощью синтаксиса доступа к атрибутам; прямой доступ к глобальным переменным модуля (из кода внутри модуля или через ссылку на словарь глобальных переменных модуля) не меняется.

Изменено в версии 3.5: Атрибут модуля __class__ теперь доступен для записи.

Добавлено в версии 3.7: Атрибуты модуля __getattr__ и __dir__.

См. также

PEP 562 — Module __getattr__ and __dir__

Описывает функции __getattr__ и __dir__ для модулей.

3.3.2.2. Реализация дескрипторов

Следующие методы применяются только в том случае, если экземпляр класса, содержащего метод (так называемого класса дескриптора), находится в классе владельце (дескриптор должен находиться либо в словаре классов владельца, либо в словаре классов одного из его родителей). В приведённых ниже примерах «атрибут» — это атрибут, имя которого является ключом свойства в __dict__ класса владельца.

object.__get__(self, instance, owner=None)

Вызывается для получения атрибута класса-владельца (доступ к атрибуту класса) или экземпляра этого класса (доступ к атрибуту экземпляра). Необязательный аргумент owner — это класс-владелец, а instance — экземпляр, через который был получен доступ к атрибуту, или None, если доступ к атрибуту осуществляется через owner.

Этот метод должен возвращать вычисленное значение атрибута или вызывать исключение AttributeError.

PEP 252 устанавливает, что __get__() может вызываться с одним или двумя аргументами. Встроенные дескрипторы Python поддерживают эту спецификацию; однако некоторые сторонние инструменты, вероятно, имеют дескрипторы, которым требуются оба аргумента. Реализация __getattribute__() в самом Python всегда передаёт оба аргумента, независимо от того, нужны ли они.

object.__set__(self, instance, value)

Вызывается для присваивания нового значения value атрибуту экземпляра instance класса-владельца.

Обратите внимание: добавление __set__() или __delete__() меняет тип дескриптора на «дескриптор данных». Подробнее см. раздел Вызов дескрипторов.

object.__delete__(self, instance)

Вызывается для удаления атрибута экземпляра instance класса-владельца.

Экземпляры дескрипторов также могут иметь атрибут __objclass__:

object.__objclass__

Модуль inspect интерпретирует атрибут __objclass__ как указание на класс, в котором был определён этот объект (правильная установка этого атрибута может помочь при динамической интроспекции атрибутов класса во время выполнения). Для вызываемых объектов он может указывать, что экземпляр заданного типа (или подкласса) ожидается или требуется в качестве первого позиционного аргумента (например, CPython устанавливает этот атрибут для несвязанных методов, реализованных на C).

3.3.2.3. Вызов дескрипторов

В общем случае дескриптор — это атрибут объекта с «поведением привязки», доступ к атрибуту которого переопределён методами протокола дескрипторов: __get__(), __set__() и __delete__(). Если для объекта определён любой из этих методов, он называется дескриптором.

По умолчанию доступ к атрибуту получает, устанавливает или удаляет атрибут из словаря объекта. Например, цепочка поиска для a.x начинается с a.__dict__['x'], затем идёт type(a).__dict__['x'] и далее продолжается по базовым классам type(a), исключая метаклассы.

Однако если найденное значение — объект, определяющий один из методов дескриптора, Python может переопределить поведение по умолчанию и вместо него вызвать метод дескриптора. Место в цепочке приоритетов, где это происходит, зависит от того, какие методы дескриптора определены и как они вызваны.

Отправная точка для вызова дескриптора — привязка, a.x. Формирование аргументов зависит от a:

Прямой вызов

Самый простой и наименее распространённый случай — когда пользовательский код напрямую вызывает метод дескриптора: x.__get__(a).

Привязка к экземпляру

При привязке к экземпляру объекта a.x преобразуется в вызов: type(a).__dict__['x'].__get__(a, type(a)).

Привязка к классу

При привязке к классу A.x преобразуется в вызов: A.__dict__['x'].__get__(None, A).

Привязка через super

Поиск по точечной нотации, например super(A, a).x, выполняет поиск в a.__class__.__mro__ базового класса B, следующего за A, а затем возвращает B.__dict__['x'].__get__(a, A). Если это не дескриптор, x возвращается без изменений.

Для привязки к экземпляру приоритет вызова дескриптора зависит от того, какие методы дескриптора определены. Дескриптор может определять любую комбинацию методов __get__(), __set__() и __delete__(). Если он не определяет __get__(), обращение к атрибуту вернёт сам объект-дескриптор, если только в словаре экземпляра объекта нет соответствующего значения. Если дескриптор определяет __set__() и/или __delete__(), он является дескриптором данных; если он не определяет ни один из этих методов — дескриптором без данных. Обычно дескрипторы данных определяют оба метода — __get__() и __set__(), тогда как дескрипторы без данных содержат только метод __get__(). Дескрипторы данных с определёнными методами __get__() и __set__() (и/или __delete__()) всегда имеют приоритет над переопределением в словаре экземпляра. Напротив, экземпляры могут переопределять дескрипторы без данных.

Методы Python (в том числе декорированные с помощью @staticmethod и @classmethod) реализованы как дескрипторы без данных. Поэтому экземпляры могут переопределять методы. Это позволяет отдельным экземплярам приобретать поведение, отличное от поведения других экземпляров того же класса.

Функция property() реализована как дескриптор данных. Поэтому экземпляры не могут переопределять поведение свойства.

3.3.2.4. __slots__

__slots__ позволяют явно объявить элементы данных (как свойства) и запретить создание __dict__ и __weakref__ (если только они явно не объявлены в __slots__ или не доступны в родительском классе).

Экономия памяти по сравнению с использованием __dict__ может быть значительной. Скорость поиска атрибутов также может заметно увеличиться.

object.__slots__

Этой переменной класса можно присвоить строку, итерируемый объект или последовательность строк с именами переменных, используемых экземплярами. __slots__ резервирует место для объявленных переменных и предотвращает автоматическое создание __dict__ и __weakref__ для каждого экземпляра.

Примечания об использовании __slots__:

  • При наследовании от класса без __slots__ атрибуты __dict__ и __weakref__ экземпляров всегда будут доступны.
  • Если переменная __dict__ отсутствует, экземплярам нельзя присваивать новые переменные, не перечисленные в определении __slots__. Попытка присвоить значение неуказанному имени переменной вызывает AttributeError. Если требуется динамическое присваивание новых переменных, добавьте '__dict__' в последовательность строк в объявлении __slots__.
  • Без переменной __weakref__ для каждого экземпляра классы, определяющие __slots__, не поддерживают weak references для своих экземпляров. Если необходима поддержка слабых ссылок, добавьте '__weakref__' в последовательность строк в объявлении __slots__.
  • __slots__ реализуются на уровне класса созданием дескрипторов для каждого имени переменной. Поэтому атрибуты класса нельзя использовать для установки значений по умолчанию переменных экземпляра, определённых в __slots__; в противном случае атрибут класса перезапишет присваивание дескриптору.
  • Действие объявления __slots__ не ограничивается классом, в котором оно определено. __slots__, объявленные в родительских классах, доступны в дочерних классах. Однако дочерние подклассы получат __dict__ и __weakref__, если они также не определят __slots__ (который должен содержать только имена дополнительных слотов).
  • Если класс определяет слот, уже определённый в базовом классе, переменная экземпляра, определённая слотом базового класса, становится недоступной (кроме случая, когда её дескриптор напрямую получен из базового класса). В результате поведение программы не определено. В будущем может быть добавлена проверка, предотвращающая это.
  • Если для класса, производного от "variable-length" built-in type, например int, bytes или tuple, определён непустой __slots__, будет вызвано исключение TypeError.
  • В качестве значения __slots__ можно использовать любой итерируемый объект, не являющийся строкой.
  • Если для присваивания __slots__ используется dictionary, его ключи будут использоваться как имена слотов. Значения словаря можно использовать для задания строк документации отдельных атрибутов; они распознаются функцией inspect.getdoc() и отображаются в выводе help().
  • Присваивание __class__ работает только в том случае, если у обоих классов одинаковое значение __slots__.
  • Множественное наследование от нескольких родительских классов со слотами допустимо, но только у одного родителя могут быть атрибуты, созданные слотами (у остальных базовых классов должны быть пустые структуры слотов); нарушение этого правила вызывает TypeError.
  • Если для __slots__ используется итератор, для каждого его значения создаётся дескриптор. Однако атрибут __slots__ будет пустым итератором.

3.3.3. Настройка создания классов

Всякий раз, когда класс наследуется от другого класса, __init_subclass__() вызывается для родительского класса. Это позволяет создавать классы, изменяющие поведение подклассов. Это тесно связано с декораторами классов, однако декораторы классов влияют только на конкретный класс, к которому они применяются, а __init_subclass__ применяется только к будущим подклассам класса, определяющего этот метод.

classmethod object.__init_subclass__(cls)

Этот метод вызывается всякий раз, когда от содержащего его класса создаётся подкласс. В этом случае cls — новый подкласс. Если он определён как обычный метод экземпляра, этот метод неявно преобразуется в метод класса.

Ключевые аргументы, переданные новому классу, передаются в __init_subclass__ родительского класса. Для совместимости с другими классами, использующими __init_subclass__, следует извлечь необходимые ключевые аргументы и передать остальные базовому классу, как показано ниже:

class Philosopher:
    def __init_subclass__(cls, /, default_name, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.default_name = default_name

class AustralianPhilosopher(Philosopher, default_name="Bruce"):
    pass

Реализация по умолчанию object.__init_subclass__ ничего не делает, но вызывает ошибку, если ей переданы какие-либо аргументы.

Примечание

Подсказка метакласса metaclass обрабатывается остальной частью механизма типов и никогда не передаётся реализациям __init_subclass__. Фактический метакласс (а не явную подсказку) можно получить с помощью type(cls).

Добавлено в версии 3.6.

При создании класса type.__new__() просматривает переменные класса и вызывает методы с хуком __set_name__().

object.__set_name__(self, owner, name)

Автоматически вызывается при создании содержащего его класса owner. Объекту присвоено имя name в этом классе:

class A:
    x = C()  # Automatically calls: x.__set_name__(A, 'x')

Если переменной класса присвоено значение после создания класса, __set_name__() автоматически вызван не будет. При необходимости __set_name__() можно вызвать напрямую:

class A:
   pass

c = C()
A.x = c                  # The hook is not called
c.__set_name__(A, 'x')   # Manually invoke the hook

Подробнее см. в разделе Создание объекта класса.

Добавлено в версии 3.6.

3.3.3.1. Метаклассы

По умолчанию классы создаются с помощью type(). Тело класса выполняется в новом пространстве имён, а имя класса локально связывается с результатом type(name, bases, namespace).

Процесс создания класса можно настроить, передав ключевой аргумент metaclass в строке определения класса или унаследовав класс, в определении которого уже присутствует такой аргумент. В следующем примере и MyClass, и MySubclass являются экземплярами Meta:

class Meta(type):
    pass

class MyClass(metaclass=Meta):
    pass

class MySubclass(MyClass):
    pass

Все остальные ключевые аргументы, указанные в определении класса, передаются всем описанным ниже операциям метакласса.

При выполнении определения класса происходят следующие шаги:

  • разрешаются записи MRO;
  • определяется подходящий метакласс;
  • подготавливается пространство имён класса;
  • выполняется тело класса;
  • создаётся объект класса.

3.3.3.2. Разрешение записей MRO

object.__mro_entries__(self, bases)

Если базовый класс, указанный в определении класса, не является экземпляром type, в нём выполняется поиск метода __mro_entries__(). Если метод __mro_entries__() найден, при создании класса базовый класс заменяется результатом вызова __mro_entries__(). Метод вызывается с исходным кортежем базовых классов, переданным параметру bases, и должен возвращать кортеж классов, которые будут использованы вместо базового класса. Возвращённый кортеж может быть пустым: в этом случае исходный базовый класс игнорируется.

См. также

types.resolve_bases()

Динамически разрешает базовые классы, не являющиеся экземплярами type.

PEP 560

Базовая поддержка модуля typing и обобщённых типов.

3.3.3.3. Определение подходящего метакласса

Подходящий метакласс для определения класса определяется следующим образом:

  • если базовые классы и явный метакласс не указаны, используется type();
  • если явный метакласс указан и он не является экземпляром type(), он непосредственно используется в качестве метакласса;
  • если в качестве явного метакласса указан экземпляр type() или определены базовые классы, используется наиболее производный метакласс.

Наиболее производный метакласс выбирается из явно указанного метакласса (если он есть) и метаклассов (то есть type(cls)) всех указанных базовых классов. Наиболее производный метакласс является подтипом всех этих метаклассов-кандидатов. Если ни один из метаклассов-кандидатов не удовлетворяет этому условию, определение класса завершается ошибкой TypeError.

3.3.3.4. Подготовка пространства имён класса

После определения подходящего метакласса подготавливается пространство имён класса. Если у метакласса есть атрибут __prepare__, он вызывается как namespace = metaclass.__prepare__(name, bases, **kwds) (дополнительные ключевые аргументы, если они есть, берутся из определения класса). Метод __prepare__ следует реализовать как classmethod. Пространство имён, возвращённое __prepare__, передаётся в __new__, однако при создании итогового объекта класса пространство имён копируется в новый dict.

Если у метакласса нет атрибута __prepare__, пространство имён класса инициализируется как пустое упорядоченное отображение.

См. также

PEP 3115 — Метаклассы в Python 3000

Введён хук пространства имён __prepare__

3.3.3.5. Выполнение тела класса

Тело класса выполняется (приблизительно) как exec(body, globals(), namespace). Ключевое отличие от обычного вызова exec() заключается в том, что лексическая область видимости позволяет телу класса (включая любые методы) обращаться к именам из текущей и внешних областей видимости, если определение класса находится внутри функции.

Однако даже если определение класса находится внутри функции, методы, определённые внутри класса, по-прежнему не могут видеть имена, определённые в области видимости класса. К переменным класса нужно обращаться через первый параметр методов экземпляра или класса либо через неявную ссылку __class__ с лексической областью видимости, описанную в следующем разделе.

3.3.3.6. Создание объекта класса

После заполнения пространства имён класса в результате выполнения тела класса объект класса создаётся вызовом metaclass(name, bases, namespace, **kwds) (передаваемые здесь дополнительные ключевые аргументы совпадают с аргументами, переданными в __prepare__).

На этот объект класса будет ссылаться форма super() без аргументов. __class__ — это неявная ссылка на замыкание, созданная компилятором, если какой-либо метод в теле класса ссылается на __class__ или super. Благодаря этому форма super() без аргументов правильно определяет создаваемый класс на основе лексической области видимости, тогда как класс или экземпляр, использованный для текущего вызова, определяется по первому аргументу, переданному методу.

Особенность реализации CPython: В CPython 3.6 и более поздних версиях ячейка __class__ передаётся метаклассу как элемент __classcell__ пространства имён класса. Если она присутствует, её необходимо передать дальше в вызов type.__new__, чтобы класс был правильно инициализирован. В противном случае в Python 3.8 возникнет ошибка RuntimeError.

При использовании метакласса по умолчанию type или любого метакласса, который в конечном счёте вызывает type.__new__, после создания объекта класса выполняются следующие дополнительные шаги настройки:

  1. Метод type.__new__ собирает все атрибуты в пространстве имён класса, определяющие метод __set_name__();
  2. Эти методы __set_name__ вызываются с создаваемым классом и присвоенным именем соответствующего атрибута;
  3. Хук __init_subclass__() вызывается для непосредственного родителя нового класса в порядке разрешения методов.

После создания объект класса передаётся декораторам класса, указанным в определении класса (если они есть), а результирующий объект связывается в локальном пространстве имён с именем определённого класса.

Когда type.__new__ создаёт новый класс, объект, переданный в качестве параметра пространства имён, копируется в новое упорядоченное отображение, а исходный объект отбрасывается. Новая копия оборачивается в прокси только для чтения, который становится атрибутом __dict__ объекта класса.

См. также

PEP 3135 — Новый super

Описывает неявную ссылку __class__ на замыкание

3.3.3.7. Применение метаклассов

Возможности применения метаклассов безграничны. Среди идей, которые уже исследовались, — перечисления, ведение журналов, проверка интерфейсов, автоматическое делегирование, автоматическое создание свойств, прокси, фреймворки и автоматическая блокировка и синхронизация ресурсов.

3.3.4. Настройка проверок экземпляров и подклассов

Следующие методы используются для переопределения поведения по умолчанию встроенных функций isinstance() и issubclass().

В частности, метакласс abc.ABCMeta реализует эти методы, чтобы разрешить добавление абстрактных базовых классов (ABC) в качестве «виртуальных базовых классов» для любого класса или типа (включая встроенные типы), в том числе для других ABC.

class.__instancecheck__(self, instance)

Возвращает true, если instance следует считать (прямым или косвенным) экземпляром class. Если этот метод определён, он вызывается для реализации isinstance(instance, class).

class.__subclasscheck__(self, subclass)

Возвращает true, если subclass следует считать (прямым или косвенным) подклассом class. Если этот метод определён, он вызывается для реализации issubclass(subclass, class).

Обратите внимание, что эти методы ищутся в типе (метаклассе) класса. Их нельзя определять как методы класса в самом классе. Это соответствует поиску специальных методов, вызываемых для экземпляров, только в данном случае экземпляр сам является классом.

См. также

PEP 3119 — Введение абстрактных базовых классов

Содержит спецификацию настройки поведения isinstance() и issubclass() с помощью __instancecheck__() и __subclasscheck__(), а также обоснование этой функциональности в контексте добавления в язык абстрактных базовых классов (см. модуль abc).

3.3.5. Имитация обобщённых типов

При использовании аннотаций типов часто бывает полезно параметризовать обобщённый тип с помощью синтаксиса квадратных скобок Python. Например, аннотация list[int] может обозначать list, все элементы которого имеют тип int.

См. также

PEP 484 — Подсказки типов

Представляет платформу Python для аннотаций типов

Обобщённые псевдонимы типов

Документация по объектам, представляющим параметризованные обобщённые классы

Generics, user-defined generics and typing.Generic

Документация о реализации обобщённых классов, которые можно параметризовать во время выполнения и которые распознаются статическими анализаторами типов.

Как правило, класс можно параметризовать, только если он определяет специальный метод класса __class_getitem__().

classmethod object.__class_getitem__(cls, key)

Возвращает объект, представляющий специализацию обобщённого класса типовыми аргументами, содержащимися в key.

Если __class_getitem__() определён в классе, он автоматически становится методом класса. Поэтому при его определении не требуется декорировать его с помощью @classmethod.

3.3.5.1. Назначение __class_getitem__

Назначение __class_getitem__() — разрешить параметризацию обобщённых классов стандартной библиотеки во время выполнения, чтобы упростить применение к этим классам подсказок типов.

Для реализации пользовательских обобщённых классов, которые можно параметризовать во время выполнения и которые распознаются статическими анализаторами типов, следует либо наследоваться от класса стандартной библиотеки, уже реализующего __class_getitem__(), либо наследоваться от typing.Generic, имеющего собственную реализацию __class_getitem__().

Пользовательские реализации __class_getitem__() в классах, определённых вне стандартной библиотеки, могут не распознаваться сторонними анализаторами типов, такими как mypy. Не рекомендуется использовать __class_getitem__() в классах для целей, не связанных с подсказками типов.

3.3.5.2. __class_getitem__ и __getitem__

Обычно при индексировании объекта с помощью квадратных скобок вызывается метод экземпляра __getitem__(), определённый в классе объекта. Однако если индексируемый объект сам является классом, вместо него может быть вызван метод класса __class_getitem__(). При правильном определении __class_getitem__() должен возвращать объект GenericAlias.

Получив выражение obj[x], интерпретатор Python выполняет примерно следующие действия, чтобы определить, следует ли вызвать __getitem__() или __class_getitem__():

from inspect import isclass

def subscribe(obj, x):
    """Return the result of the expression 'obj[x]'"""

    class_of_obj = type(obj)

    # If the class of obj defines __getitem__,
    # call class_of_obj.__getitem__(obj, x)
    if hasattr(class_of_obj, '__getitem__'):
        return class_of_obj.__getitem__(obj, x)

    # Else, if obj is a class and defines __class_getitem__,
    # call obj.__class_getitem__(x)
    elif isclass(obj) and hasattr(obj, '__class_getitem__'):
        return obj.__class_getitem__(x)

    # Else, raise an exception
    else:
        raise TypeError(
            f"'{class_of_obj.__name__}' object is not subscriptable"
        )

В Python все классы сами являются экземплярами других классов. Класс класса называется метаклассом, и у большинства классов метаклассом является класс type. type не определяет __getitem__(), поэтому выражения list[int], dict[str, float] и tuple[str, bytes] приводят к вызову __class_getitem__():

>>> # list has class "type" as its metaclass, like most classes:
>>> type(list)
<class 'type'>
>>> type(dict) == type(list) == type(tuple) == type(str) == type(bytes)
True
>>> # "list[int]" calls "list.__class_getitem__(int)"
>>> list[int]
list[int]
>>> # list.__class_getitem__ returns a GenericAlias object:
>>> type(list[int])
<class 'types.GenericAlias'>

Однако если у класса есть пользовательский метакласс, определяющий __getitem__(), индексирование класса может привести к другому поведению. Пример этого можно найти в модуле enum:

>>> from enum import Enum
>>> class Menu(Enum):
...     """A breakfast menu"""
...     SPAM = 'spam'
...     BACON = 'bacon'
...
>>> # Enum classes have a custom metaclass:
>>> type(Menu)
<class 'enum.EnumMeta'>
>>> # EnumMeta defines __getitem__,
>>> # so __class_getitem__ is not called,
>>> # and the result is not a GenericAlias object:
>>> Menu['SPAM']
<Menu.SPAM: 'spam'>
>>> type(Menu['SPAM'])
<enum 'Menu'>

См. также

PEP 560 — Базовая поддержка модуля typing и обобщённых типов

Представляет __class_getitem__() и описывает, в каких случаях индексирование приводит к вызову __class_getitem__() вместо __getitem__()

3.3.6. Имитация вызываемых объектов

object.__call__(self[, args...])

Вызывается, когда экземпляр «вызывается» как функция; если этот метод определён, x(arg1, arg2, ...) приблизительно соответствует type(x).__call__(x, arg1, ...).

3.3.7. Эмуляция типов контейнеров

Для реализации объектов-контейнеров можно определить следующие методы. Контейнеры обычно представляют собой последовательности (например, lists или tuples) либо отображения (например, dictionaries), но могут представлять и другие типы контейнеров. Первый набор методов используется для эмуляции последовательности или отображения; различие в том, что для последовательности допустимыми ключами должны быть целые числа k, для которых 0 <= k < N, где N — длина последовательности, либо объекты slice, задающие диапазон элементов. Также рекомендуется, чтобы отображения предоставляли методы keys(), values(), items(), get(), clear(), setdefault(), pop(), popitem(), copy() и update(), работающие аналогично соответствующим методам стандартных объектов Python dictionary. Модуль collections.abc предоставляет MutableMapping — абстрактный базовый класс, который помогает создать эти методы на основе набора методов __getitem__(), __setitem__(), __delitem__() и keys(). Изменяемые последовательности должны предоставлять методы append(), count(), index(), extend(), insert(), pop(), remove(), reverse() и sort(), как стандартные объекты Python list. Наконец, типы последовательностей должны реализовывать сложение (то есть конкатенацию) и умножение (то есть повторение), определяя описанные ниже методы __add__(), __radd__(), __iadd__(), __mul__(), __rmul__() и __imul__(); другие числовые операторы определять не следует. Рекомендуется, чтобы и отображения, и последовательности реализовывали метод __contains__(), обеспечивающий эффективное использование оператора in; для отображений in должен искать среди ключей отображения, а для последовательностей — среди значений. Также рекомендуется, чтобы и отображения, и последовательности реализовывали метод __iter__(), обеспечивающий эффективный перебор контейнера; для отображений __iter__() должен перебирать ключи объекта, а для последовательностей — значения.

object.__len__(self)

Вызывается для реализации встроенной функции len(). Должен возвращать длину объекта — целое число >= 0. Кроме того, объект, у которого не определён метод __bool__() и чей метод __len__() возвращает ноль, считается ложным в логическом контексте.

Особенность реализации CPython: В CPython длина не должна превышать sys.maxsize. Если длина больше sys.maxsize, некоторые возможности (например, len()) могут вызвать исключение OverflowError. Чтобы при проверке истинности не возникало исключение OverflowError, объект должен определять метод __bool__().

object.__length_hint__(self)

Вызывается для реализации operator.length_hint(). Должен возвращать приблизительную длину объекта (которая может быть больше или меньше фактической длины). Длина должна быть целым числом >= 0. Возвращаемым значением также может быть NotImplemented; в этом случае оно обрабатывается так же, как если бы метода __length_hint__ вовсе не существовало. Этот метод служит исключительно для оптимизации и не требуется для корректной работы.

Добавлено в версии 3.4.

Примечание

Срезы обрабатываются исключительно следующими тремя методами. Вызов вида

a[1:2] = b

преобразуется в

a[slice(1, 2, None)] = b

и так далее. Пропущенные элементы среза всегда заполняются значением None.

object.__getitem__(self, key)

Вызывается для реализации вычисления self[key]. Для типов последовательностей допустимыми ключами должны быть целые числа. При желании можно также поддержать объекты slice. Поддержка отрицательных индексов необязательна. Если key имеет недопустимый тип, можно вызвать исключение TypeError; если key выходит за пределы множества индексов последовательности (с учётом особой интерпретации отрицательных значений), следует вызвать исключение IndexError. Для типов отображений, если key отсутствует (то есть его нет в контейнере), следует вызвать исключение KeyError.

Примечание

Циклы for ожидают, что для недопустимых индексов будет вызвано исключение IndexError, чтобы можно было корректно определить конец последовательности.

Примечание

При индексации класса вместо __getitem__() может вызываться специальный метод класса __class_getitem__(). Подробности см. в разделе __class_getitem__ и __getitem__.

object.__setitem__(self, key, value)

Вызывается для реализации присваивания в self[key]. Применимо то же примечание, что и для __getitem__(). Этот метод следует реализовывать только для отображений, если объекты допускают изменение значений существующих ключей или добавление новых ключей, либо для последовательностей, если их элементы можно заменять. Для недопустимых значений key следует вызывать те же исключения, что и для метода __getitem__().

object.__delitem__(self, key)

Вызывается для реализации удаления self[key]. Применимо то же примечание, что и для __getitem__(). Этот метод следует реализовывать только для отображений, если объекты допускают удаление ключей, либо для последовательностей, если из них можно удалять элементы. Для недопустимых значений key следует вызывать те же исключения, что и для метода __getitem__().

object.__missing__(self, key)

Вызывается методом dict.__getitem__() для реализации self[key] в подклассах dict, если ключ отсутствует в словаре.

object.__iter__(self)

Этот метод вызывается, когда для контейнера требуется итератор. Метод должен возвращать новый объект-итератор, который может перебирать все объекты в контейнере. Для отображений он должен перебирать ключи контейнера.

object.__reversed__(self)

Вызывается встроенной функцией reversed() (если метод определён) для реализации обратного перебора. Метод должен возвращать новый объект-итератор, который перебирает все объекты контейнера в обратном порядке.

Если метод __reversed__() не предоставлен, встроенная функция reversed() использует протокол последовательности (__len__() и __getitem__()). Объектам, поддерживающим протокол последовательности, следует предоставлять __reversed__() только в том случае, если они могут реализовать его эффективнее, чем встроенная функция reversed().

Операторы проверки принадлежности (in и not in) обычно реализуются перебором контейнера. Однако объекты-контейнеры могут предоставлять следующий специальный метод с более эффективной реализацией, которая также не требует, чтобы объект был итерируемым.

object.__contains__(self, item)

Вызывается для реализации операторов проверки принадлежности. Должен возвращать истину, если item содержится в self, и ложь в противном случае. Для объектов-отображений следует проверять ключи отображения, а не значения или пары «ключ-значение».

Если объект не определяет __contains__(), проверка принадлежности сначала пытается выполнить перебор с помощью __iter__(), а затем использует старый протокол перебора последовательности через __getitem__(); см. этот раздел справочника по языку.

3.3.8. Эмуляция числовых типов

Для эмуляции числовых объектов можно определить следующие методы. Методы, соответствующие операциям, которые не поддерживаются реализуемым типом числа (например, побитовые операции для нецелых чисел), следует оставить неопределёнными.

object.__add__(self, other)
object.__sub__(self, other)
object.__mul__(self, other)
object.__matmul__(self, other)
object.__truediv__(self, other)
object.__floordiv__(self, other)
object.__mod__(self, other)
object.__divmod__(self, other)
object.__pow__(self, other[, modulo])
object.__lshift__(self, other)
object.__rshift__(self, other)
object.__and__(self, other)
object.__xor__(self, other)
object.__or__(self, other)

Эти методы вызываются для реализации бинарных арифметических операций (+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |). Например, для вычисления выражения x + y, где x — экземпляр класса с методом __add__(), вызывается type(x).__add__(x, y). Метод __divmod__() должен быть эквивалентен использованию __floordiv__() и __mod__(); он не должен быть связан с __truediv__(). Обратите внимание: если требуется поддержка трёхаргументной формы встроенной функции pow(), метод __pow__() должен принимать необязательный третий аргумент.

Если один из этих методов не поддерживает операцию с переданными аргументами, он должен возвращать NotImplemented.

object.__radd__(self, other)
object.__rsub__(self, other)
object.__rmul__(self, other)
object.__rmatmul__(self, other)
object.__rtruediv__(self, other)
object.__rfloordiv__(self, other)
object.__rmod__(self, other)
object.__rdivmod__(self, other)
object.__rpow__(self, other[, modulo])
object.__rlshift__(self, other)
object.__rrshift__(self, other)
object.__rand__(self, other)
object.__rxor__(self, other)
object.__ror__(self, other)

Эти методы вызываются для реализации бинарных арифметических операций (+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |) с переставленными операндами. Эти функции вызываются только в том случае, если левый операнд не поддерживает соответствующую операцию [3] и типы операндов различаются. [4] Например, для вычисления выражения x - y, где y — экземпляр класса с методом __rsub__(), вызывается type(y).__rsub__(y, x), если type(x).__sub__(x, y) возвращает NotImplemented.

Обратите внимание: трёхаргументная форма pow() не будет пытаться вызвать __rpow__() (правила приведения типов стали бы слишком сложными).

Примечание

Если тип правого операнда является подклассом типа левого операнда и этот подкласс предоставляет собственную реализацию отражённого метода для данной операции, этот метод вызывается раньше неотражённого метода левого операнда. Такое поведение позволяет подклассам переопределять операции своих базовых классов.

object.__iadd__(self, other)
object.__isub__(self, other)
object.__imul__(self, other)
object.__imatmul__(self, other)
object.__itruediv__(self, other)
object.__ifloordiv__(self, other)
object.__imod__(self, other)
object.__ipow__(self, other[, modulo])
object.__ilshift__(self, other)
object.__irshift__(self, other)
object.__iand__(self, other)
object.__ixor__(self, other)
object.__ior__(self, other)

Эти методы вызываются для реализации составных арифметических операций присваивания (+=, -=, *=, @=, /=, //=, %=, **=, <<=, >>=, &=, ^=, |=). Эти методы должны по возможности выполнять операцию на месте (изменяя self) и возвращать результат (которым может быть, но не обязательно является, self). Если конкретный метод не определён или возвращает NotImplemented, составная операция присваивания использует обычные методы. Например, если x — экземпляр класса с методом __iadd__(), то x += y эквивалентно x = x.__iadd__(y) . Если __iadd__() не существует или x.__iadd__(y) возвращает NotImplemented, рассматриваются x.__add__(y) и y.__radd__(x), как и при вычислении x + y. В некоторых ситуациях составное присваивание может приводить к неожиданным ошибкам (см. Почему a_tuple[i] += [‘item’] вызывает исключение, хотя сложение работает?), но такое поведение является частью модели данных.

object.__neg__(self)
object.__pos__(self)
object.__abs__(self)
object.__invert__(self)

Вызываются для реализации унарных арифметических операций (-, +, abs() и ~).

object.__complex__(self)
object.__int__(self)
object.__float__(self)

Вызываются для реализации встроенных функций complex(), int() и float(). Должны возвращать значение соответствующего типа.

object.__index__(self)

Вызывается для реализации operator.index(), а также всякий раз, когда Python требуется преобразовать числовой объект в целочисленный без потери данных (например, при создании среза или вызове встроенных функций bin(), hex() и oct()). Наличие этого метода означает, что числовой объект относится к целочисленному типу. Метод должен возвращать целое число.

Если методы __int__(), __float__() и __complex__() не определены, соответствующие встроенные функции int(), float() и complex() используют __index__() как запасной вариант.

object.__round__(self[, ndigits])
object.__trunc__(self)
object.__floor__(self)
object.__ceil__(self)

Вызываются для реализации встроенной функции round() и функций модуля math — trunc(), floor() и ceil(). Если в __round__() не передан аргумент ndigits, все эти методы должны возвращать значение объекта, усечённое до Integral (обычно до int).

Если не определены ни __int__(), ни __index__(), встроенная функция int() использует __trunc__() как запасной вариант.

Изменено в версии 3.11: Использование метода __trunc__() в качестве запасного варианта для int() объявлено устаревшим.

3.3.9. Менеджеры контекста оператора with

Менеджер контекста — это объект, определяющий контекст выполнения, который устанавливается при выполнении оператора with. Менеджер контекста управляет входом в нужный контекст выполнения и выходом из него при выполнении блока кода. Обычно менеджеры контекста вызываются с помощью оператора with (описанного в разделе Оператор with), но их методы также можно вызывать напрямую.

Типичные случаи использования менеджеров контекста включают сохранение и восстановление различных видов глобального состояния, блокировку и разблокировку ресурсов, закрытие открытых файлов и т. д.

Дополнительные сведения о менеджерах контекста см. в разделе Типы менеджеров контекста.

object.__enter__(self)

Войти в контекст выполнения, связанный с этим объектом. Оператор with связывает возвращаемое этим методом значение с целевой переменной или переменными, указанными в предложении as оператора, если оно есть.

object.__exit__(self, exc_type, exc_value, traceback)

Выйти из контекста выполнения, связанного с этим объектом. Параметры описывают исключение, из-за которого был завершён контекст. Если контекст был завершён без исключения, все три аргумента будут равны None.

Если передано исключение и метод должен подавить его (то есть предотвратить его распространение), метод должен вернуть истинное значение. В противном случае исключение будет обработано обычным образом при выходе из этого метода.

Обратите внимание: методы __exit__() не должны повторно возбуждать переданное исключение; это обязанность вызывающего кода.

См. также

PEP 343 — оператор «with»

Спецификация, предыстория и примеры оператора with в Python.

3.3.10. Настройка позиционных аргументов при сопоставлении с образцом класса

По умолчанию при использовании имени класса в образце позиционные аргументы не допускаются, то есть case MyClass(x, y) обычно недопустимо без специальной поддержки в MyClass. Чтобы использовать такой образец, класс должен определить атрибут __match_args__.

object.__match_args__

Этой переменной класса можно присвоить кортеж строк. Когда этот класс используется в образце класса с позиционными аргументами, каждый позиционный аргумент преобразуется в именованный аргумент, в качестве имени которого используется соответствующее значение из __match_args__. Отсутствие этого атрибута равносильно его установке в значение ().

Например, если MyClass.__match_args__ равно ("left", "center", "right"), это означает, что case MyClass(x, y) эквивалентно case MyClass(left=x, center=y). Обратите внимание: количество аргументов в образце должно быть меньше или равно количеству элементов в __match_args__; если оно больше, попытка сопоставления с образцом вызовет исключение TypeError.

Добавлено в версии 3.10.

См. также

PEP 634 — структурное сопоставление с образцом

Спецификация оператора match в Python.

3.3.11. Поиск специальных методов

Для пользовательских классов гарантируется корректная работа неявных вызовов специальных методов, только если они определены для типа объекта, а не в словаре экземпляра объекта. Именно поэтому следующий код вызывает исключение:

>>> class C:
...     pass
...
>>> c = C()
>>> c.__len__ = lambda: 5
>>> len(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'C' has no len()

Причина такого поведения заключается в существовании ряда специальных методов, таких как __hash__() и __repr__(), реализованных всеми объектами, включая объекты типов. Если бы при неявном поиске этих методов использовался обычный механизм поиска, они не работали бы при вызове для самого объекта типа:

>>> 1 .__hash__() == hash(1)
True
>>> int.__hash__() == hash(int)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor '__hash__' of 'int' object needs an argument

Неправильную попытку вызвать несвязанный метод класса таким способом иногда называют «путаницей метакласса». Её можно избежать, пропуская экземпляр при поиске специальных методов:

>>> type(1).__hash__(1) == hash(1)
True
>>> type(int).__hash__(int) == hash(int)
True

Помимо пропуска атрибутов экземпляра для обеспечения корректности, неявный поиск специальных методов обычно также пропускает метод __getattribute__(), даже если он определён в метаклассе объекта:

>>> class Meta(type):
...     def __getattribute__(*args):
...         print("Metaclass getattribute invoked")
...         return type.__getattribute__(*args)
...
>>> class C(object, metaclass=Meta):
...     def __len__(self):
...         return 10
...     def __getattribute__(*args):
...         print("Class getattribute invoked")
...         return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__()                 # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c)          # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c)                      # Implicit lookup
10

Такой обход механизма __getattribute__() предоставляет интерпретатору широкие возможности для оптимизации скорости, но уменьшает гибкость при работе со специальными методами (специальный метод должен быть установлен непосредственно в объекте класса, чтобы интерпретатор вызывал его единообразно).

3.4. Сопрограммы

3.4.1. Объекты, поддерживающие await

Объект, поддерживающий await, обычно реализует метод __await__(). Объекты сопрограмм, возвращаемые функциями async def, поддерживают await.

Примечание

Объекты итераторов-генераторов, возвращаемые генераторами, декорированными с помощью types.coroutine(), также поддерживают await, но не реализуют __await__().

object.__await__(self)

Должен возвращать итератор. Предназначен для реализации объектов, поддерживающих await. Например, asyncio.Future реализует этот метод для совместимости с выражением await.

Примечание

Язык не накладывает никаких ограничений на тип или значение объектов, выдаваемых итератором, возвращаемым __await__, поскольку это зависит от реализации асинхронной среды выполнения (например, asyncio), которая управляет объектом, поддерживающим await.

Добавлено в версии 3.5.

См. также

PEP 492: дополнительные сведения об объектах, поддерживающих await.

3.4.2. Объекты сопрограмм

Объекты сопрограмм — это объекты, поддерживающие await. Выполнением сопрограммы можно управлять, вызывая __await__() и перебирая полученный результат. Когда выполнение сопрограммы завершается возвратом значения, итератор вызывает исключение StopIteration, а атрибут value этого исключения содержит возвращаемое значение. Если сопрограмма вызывает исключение, итератор передаёт его дальше. Сопрограммы не должны напрямую вызывать необработанные исключения StopIteration.

У сопрограмм также есть перечисленные ниже методы, аналогичные методам генераторов (см. раздел Методы итератора-генератора). Однако, в отличие от генераторов, сопрограммы напрямую не поддерживают итерацию.

Изменено в версии 3.5.2: Повторное ожидание одной и той же сопрограммы вызывает RuntimeError.

coroutine.send(value)

Запускает или возобновляет выполнение сопрограммы. Если value равно None, это эквивалентно продвижению итератора, возвращённого __await__(). Если value не равно None, этот метод делегирует выполнение методу send() итератора, из-за которого выполнение сопрограммы было приостановлено. Результат (возвращаемое значение, StopIteration или другое исключение) совпадает с результатом перебора возвращаемого значения __await__(), описанного выше.

coroutine.throw(value)
coroutine.throw(type[, value[, traceback]])

Вызывает указанное исключение в сопрограмме. Если у итератора, из-за которого выполнение сопрограммы было приостановлено, есть метод throw(), этот метод делегирует ему выполнение. В противном случае исключение вызывается в точке приостановки. Результат (возвращаемое значение, StopIteration или другое исключение) совпадает с результатом перебора возвращаемого значения __await__(), описанного выше. Если исключение не перехвачено в сопрограмме, оно передаётся вызывающему коду.

coroutine.close()

Заставляет сопрограмму выполнить очистку и завершиться. Если выполнение сопрограммы приостановлено, этот метод сначала делегирует выполнение методу close() итератора, из-за которого оно было приостановлено, если такой метод есть. Затем в точке приостановки вызывается GeneratorExit, что немедленно заставляет сопрограмму выполнить очистку. Наконец, сопрограмма помечается как завершившая выполнение, даже если её выполнение ещё не начиналось.

Объекты сопрограмм автоматически закрываются описанным выше способом перед уничтожением.

3.4.3. Асинхронные итераторы

Асинхронный итератор может вызывать асинхронный код в своём методе __anext__.

Асинхронные итераторы можно использовать в операторе async for.

object.__aiter__(self)

Должен возвращать объект асинхронного итератора.

object.__anext__(self)

Должен возвращать объект, поддерживающий await, результатом которого будет следующее значение итератора. По завершении итерации должен вызывать исключение StopAsyncIteration.

Пример асинхронного итерируемого объекта:

class Reader:
    async def readline(self):
        ...

    def __aiter__(self):
        return self

    async def __anext__(self):
        val = await self.readline()
        if val == b'':
            raise StopAsyncIteration
        return val

Добавлено в версии 3.5.

Изменено в версии 3.7: До Python 3.7 метод __aiter__() мог возвращать объект, поддерживающий await, результатом которого был асинхронный итератор.

Начиная с Python 3.7, метод __aiter__() должен возвращать объект асинхронного итератора. Возврат любого другого объекта приведёт к исключению TypeError.

3.4.4. Асинхронные менеджеры контекста

Асинхронный менеджер контекста — это менеджер контекста, который может приостанавливать выполнение в своих методах __aenter__ и __aexit__.

Асинхронные менеджеры контекста можно использовать в операторе async with.

object.__aenter__(self)

Семантически аналогичен __enter__(); единственное отличие заключается в том, что он должен возвращать объект, поддерживающий await.

object.__aexit__(self, exc_type, exc_value, traceback)

Семантически аналогичен __exit__(); единственное отличие заключается в том, что он должен возвращать объект, поддерживающий await.

Пример класса асинхронного менеджера контекста:

class AsyncContextManager:
    async def __aenter__(self):
        await log('entering context')

    async def __aexit__(self, exc_type, exc, tb):
        await log('exiting context')

Добавлено в версии 3.5.

Сноски

[1]

В некоторых случаях тип объекта действительно можно изменить при определённых контролируемых условиях. Однако обычно это не рекомендуется, поскольку неправильная обработка может привести к очень странному поведению.

[2]

Для методов __hash__(), __iter__(), __reversed__() и __contains__() предусмотрена специальная обработка; остальные по-прежнему вызовут исключение TypeError, но причиной может стать поведение, при котором None не является вызываемым объектом.

[3]

«Не поддерживает» здесь означает, что у класса нет такого метода или что метод возвращает NotImplemented. Если нужно задействовать отражённый метод правого операнда, не присваивайте методу значение None: это приведёт к обратному эффекту и явно заблокирует такой переход.

[4]

Для операндов одного типа предполагается, что если обычный метод, например __add__(), завершается неудачей, то операция в целом не поддерживается, поэтому отражённый метод не вызывается.

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

Spec-Zone.ru

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