Содержание страницы
3. Модель данных¶Data model
3.1. Объекты, значения и типы¶Objects, values and types
Объекты – это абстракция данных в 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. Стандартная иерархия типов¶The standard type hierarchy
Ниже приведён список типов, встроенных в Python. Модули расширения (написанные на C, Java или других языках в зависимости от реализации) могут определять дополнительные типы. Будущие версии Python могут добавлять типы в иерархию (например, рациональные числа, эффективно хранимые массивы целых чисел и т.д.), хотя такие дополнения чаще будут предоставляться через стандартную библиотеку.
Некоторые описания типов ниже содержат абзац, перечисляющий «специальные атрибуты». Это атрибуты, обеспечивающие доступ к реализации и не предназначенные для общего использования. Их определение может измениться в будущем.
- None
Этот тип имеет единственное значение. Существует только один объект с этим значением. Доступ к этому объекту осуществляется через встроенное имя
None. Он используется для обозначения отсутствия значения во многих ситуациях, например, возвращается из функций, которые явно ничего не возвращают. Его логическое значение – ложь.- NotImplemented
Этот тип имеет единственное значение. Существует единственный объект с этим значением. Доступ к этому объекту осуществляется через встроенное имя
NotImplemented. Числовые методы и методы расширенного сравнения должны возвращать это значение, если они не реализуют операцию для предоставленных операндов. (В этом случае интерпретатор попробует применить отражённую операцию или другой запасной вариант в зависимости от оператора.) Его истинностное значение – True.См. Реализация арифметических операций для получения дополнительных сведений.
- Ellipsis
Этот тип имеет единственное значение. Существует только один объект с этим значением. Доступ к объекту осуществляется через литерал
...или встроенное имяEllipsis. Его логическое значение – истина.numbers.NumberОни создаются числовыми литералами и возвращаются в результате работы арифметических операторов и встроенных арифметических функций. Числовые объекты неизменяемы; после создания их значение никогда не меняется. Числа в Python, конечно, тесно связаны с математическими числами, но подвержены ограничениям числового представления в компьютерах.
Python различает целые числа, числа с плавающей запятой и комплексные числа:
numbers.IntegralОни представляют элементы из математического множества целых чисел (положительных и отрицательных).
Существует два типа целых чисел:
Целые числа (
int)Они представляют числа в неограниченном диапазоне, ограниченном лишь доступной (виртуальной) памятью. Для операций сдвига и маскирования используется двоичное представление, а отрицательные числа представляются в варианте дополнительного кода, который создаёт иллюзию бесконечной строки знаковых битов, уходящей влево.- Булевы значения (
bool) Они представляют истинностные значения False и True. Два объекта, представляющие значения
FalseиTrue, являются единственными булевыми объектами. Булев тип является подтипом целочисленного типа, и булевы значения ведут себя как значения 0 и 1 соответственно почти во всех контекстах, за исключением того, что при преобразовании в строку возвращаются строки"False"или"True"соответственно.
Правила представления целых чисел призваны давать наиболее осмысленную интерпретацию операций сдвига и маскирования, в которых участвуют отрицательные целые числа.
- Булевы значения (
numbers.Real(float)Эти числа представляют собой машинные числа с плавающей запятой двойной точности. Допустимый диапазон и обработка переполнения определяются нижележащей архитектурой машины (и реализацией на C или Java). Python не поддерживает числа с плавающей запятой одинарной точности; экономия процессора и памяти, которая обычно является причиной их использования, ничтожна по сравнению с накладными расходами на использование объектов в Python, поэтому нет смысла усложнять язык двумя видами чисел с плавающей запятой.
numbers.Complex(complex)Они представляют комплексные числа как пару машинных чисел с плавающей запятой двойной точности. Те же предостережения применяются, что и для чисел с плавающей запятой. Действительная и мнимая части комплексного числа
zмогут быть получены через атрибуты только для чтенияz.realиz.imag.
- Последовательности
Они представляют собой конечные упорядоченные множества, индексированные неотрицательными числами. Встроенная функция
len()возвращает количество элементов последовательности. Когда длина последовательности равна n, набор индексов содержит числа 0, 1, …, n-1. Элемент i последовательности a выбирается с помощьюa[i].Последовательности также поддерживают срезы:
a[i:j]выбирает все элементы с индексом k, таким что i<=k<j. При использовании в качестве выражения срез представляет собой последовательность того же типа. Это подразумевает, что набор индексов перенумеровывается так, чтобы начинаться с 0.Некоторые последовательности также поддерживают «расширенную нарезку» с третьим параметром «шаг»:
a[i:j:k]выбирает все элементы a с индексом x, гдеx = i + n*k, n>=0и i<=x<j.Последовательности различаются по изменяемости:
- Неизменяемые последовательности
Объект неизменяемого типа последовательности не может измениться после создания. (Если объект содержит ссылки на другие объекты, эти другие объекты могут быть изменяемыми и могут изменяться; однако совокупность объектов, на которые непосредственно ссылается неизменяемый объект, измениться не может.)
Следующие типы являются неизменяемыми последовательностями:
- Строки
Строка – это последовательность значений, представляющих кодовые точки 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 (например,
b'abc') и встроенная функцияbytes()используются для создания объектов bytes. Кроме того, объекты bytes можно декодировать в строки с помощью методаdecode().
- Изменяемые последовательности
Изменяемые последовательности можно изменять после их создания. Обозначения подписки и срезов можно использовать как цель для присваивания и операторов
del(удаление).В настоящее время существует два встроенных изменяемых типа последовательностей:
- Списки
Элементами списка являются произвольные объекты Python. Списки создаются путём помещения списка выражений, разделённых запятыми, в квадратные скобки. (Обратите внимание, что для создания списков длины 0 или 1 не требуется особых случаев.)
- Байтовые массивы
Объект bytearray – это изменяемый массив. Они создаются с помощью встроенного конструктора
bytearray(). Помимо изменяемости (и, следовательно, невозможности хеширования), bytearray предоставляет тот же интерфейс и функциональность, что и неизменяемые объекты bytes.
Модуль расширения
arrayпредоставляет дополнительный пример изменяемого типа последовательности, как и модульcollections.
- Типы множеств
Они представляют неупорядоченные, конечные множества уникальных, неизменяемых объектов. Поэтому к ним нельзя обратиться по индексу. Однако их можно перебирать, а встроенная функция
len()возвращает количество элементов в множестве. Обычное применение множеств – быстрая проверка принадлежности, удаление дубликатов из последовательности и выполнение математических операций, таких как пересечение, объединение, разность и симметрическая разность.Для элементов множества действуют те же правила неизменяемости, что и для ключей словаря. Обратите внимание, что числовые типы следуют обычным правилам числового сравнения: если два числа считаются равными (например,
1и1.0), только одно из них может содержаться в множестве.В настоящее время существует два встроенных типа множеств:
- Множества
Они представляют изменяемое множество. Они создаются встроенным конструктором
set()и могут быть изменены впоследствии с помощью нескольких методов, таких какadd().- Неизменяемые множества
Они представляют неизменяемое множество. Они создаются встроенным конструктором
frozenset(). Поскольку frozenset неизменяем и хешируем, его можно снова использовать как элемент другого множества или как ключ словаря.
- Отображения
Они представляют конечные наборы объектов, индексированных произвольными наборами индексов. Обозначение индекса
a[k]выбирает элемент, индексированныйk, из отображенияa; это можно использовать в выражениях и как цель присваивания или операторовdel. Встроенная функцияlen()возвращает количество элементов в отображении.В настоящее время существует один встроенный тип отображения:
- Словари
Они представляют конечные наборы объектов, индексированных почти произвольными значениями. Единственные типы значений, неприемлемые в качестве ключей, – это значения, содержащие списки, словари или другие изменяемые типы, которые сравниваются по значению, а не по идентичности объекта. Причина в том, что эффективная реализация словарей требует, чтобы хеш-значение ключа оставалось постоянным. Числовые типы, используемые для ключей, подчиняются обычным правилам числового сравнения: если два числа считаются равными (например,
1и1.0), то они могут использоваться взаимозаменяемо для индексации одной и той же записи словаря.Словари изменяемы; их можно создать с помощью обозначения
{...}(см. раздел Отображения словарей).Модули расширения
dbm.ndbmиdbm.gnuпредоставляют дополнительные примеры типов отображений, как и модульcollections.
- Вызываемые типы
Это типы, к которым применима операция вызова функции (см. раздел Вызовы):
- Определяемые пользователем функции
Объект пользовательской функции создаётся определением функции (см. раздел Определения функций). Она должна вызываться со списком аргументов, содержащим то же количество элементов, что и список формальных параметров функции.
Специальные атрибуты:
Атрибут Значение __doc__Строка документации функции, или None, если отсутствует; не наследуется подклассамиДоступно для записи __name__Имя функции Доступно для записи __qualname__Полное имя функции
Новое в версии 3.3.
Доступно для записи __module__Имя модуля, в котором была определена функция, или None, если недоступно.Доступно для записи __defaults__Кортеж, содержащий значения аргументов по умолчанию для тех аргументов, у которых есть значения по умолчанию, или None, если ни один аргумент не имеет значения по умолчаниюДоступно для записи __code__Объект кода, представляющий скомпилированное тело функции. Доступно для записи __globals__Ссылка на словарь, содержащий глобальные переменные функции – глобальное пространство имён модуля, в котором функция была определена. Только для чтения __dict__Пространство имён, поддерживающее произвольные атрибуты функции. Доступно для записи __closure__Noneили кортеж ячеек, содержащих привязки для свободных переменных функции.Только для чтения __annotations__Словарь, содержащий аннотации параметров. Ключи словаря – имена параметров, а 'return'– для аннотации возвращаемого значения, если она указана.Доступно для записи __kwdefaults__Словарь, содержащий значения по умолчанию для параметров, передаваемых только по ключу. Доступно для записи Большинство атрибутов, помеченных как «Доступно для записи», проверяют тип присваиваемого значения.
Объекты функций также поддерживают получение и установку произвольных атрибутов, которые можно использовать, например, для присоединения метаданных к функциям. Для получения и установки таких атрибутов используется обычная точечная нотация. Обратите внимание, что текущая реализация поддерживает атрибуты функций только для пользовательских функций. Атрибуты функций для встроенных функций могут быть добавлены в будущем.
Дополнительную информацию об определении функции можно получить из её объекта code; см. описание внутренних типов ниже.
- Методы экземпляра
Объект метода экземпляра сочетает в себе класс, экземпляр класса и любой вызываемый объект (обычно функцию, определённую пользователем).
Специальные атрибуты только для чтения:
__self__– объект экземпляра класса,__func__– объект функции;__doc__– документация метода (то же, что и__func__.__doc__);__name__– имя метода (то же, что и__func__.__name__);__module__– имя модуля, в котором определён метод, илиNone, если недоступно.Методы также поддерживают доступ (но не установку) произвольных атрибутов функции на базовом объекте функции.
Объекты пользовательских методов могут создаваться при получении атрибута класса (возможно, через экземпляр этого класса), если этот атрибут является пользовательским объектом функции или объектом метода класса.
Когда объект метода экземпляра создаётся путём извлечения пользовательского объекта функции из класса через один из его экземпляров, его атрибут
__self__является экземпляром, и такой метод называется связанным. Атрибут__func__нового метода – это исходный объект функции.Когда пользовательский объект метода создаётся путём получения другого объекта метода из класса или экземпляра, поведение аналогично объекту функции, за исключением того, что атрибут
__func__нового экземпляра – это не исходный объект метода, а его атрибут__func__.Когда объект метода экземпляра создаётся путём извлечения объекта метода класса из класса или экземпляра, его атрибут
__self__является самим классом, а его атрибут__func__– объектом функции, лежащим в основе метода класса.При вызове объекта метода экземпляра вызывается базовая функция (
__func__), при этом экземпляр класса (__self__) вставляется перед списком аргументов. Например, когдаC– это класс, содержащий определение функцииf(), аx– экземплярC, вызовx.f(1)эквивалентен вызовуC.f(x, 1).Когда объект метода экземпляра создаётся на основе объекта метода класса, «экземпляр класса», хранящийся в
__self__, на самом деле будет самим классом, так что вызовx.f(1)илиC.f(1)эквивалентен вызовуf(C,1), гдеf– это базовая функция.Обратите внимание, что преобразование объекта функции в объект метода экземпляра происходит каждый раз при получении атрибута из экземпляра. В некоторых случаях полезной оптимизацией является присвоение атрибута локальной переменной и вызов этой локальной переменной. Также заметьте, что это преобразование происходит только для пользовательских функций; другие вызываемые объекты (и все невызываемые объекты) извлекаются без преобразования. Важно также отметить, что пользовательские функции, которые являются атрибутами экземпляра класса, не преобразуются в связанные методы; это происходит только, когда функция является атрибутом класса.
- Функции-генераторы
Функция или метод, использующие оператор
yield(см. раздел Оператор yield), называется функцией-генератором. При вызове такая функция всегда возвращает объект-итератор, который можно использовать для выполнения тела функции: вызов методаiterator.__next__()итератора заставляет функцию выполняться до тех пор, пока она не предоставит значение с помощью оператораyield. Когда функция выполняет операторreturnили завершается, возбуждается исключениеStopIteration, и итератор достигает конца набора возвращаемых значений.- Корутинные функции
Функция или метод, определённые с помощью
async def, называются корутинной функцией. Такая функция при вызове возвращает объект корутины. Она может содержать выраженияawait, а также инструкцииasync withиasync for. См. также раздел Объекты корутин.- Встроенные функции
Объект встроенной функции – это обёртка вокруг функции на C. Примерами встроенных функций являются
len()иmath.sin()(math– стандартный встроенный модуль). Количество и тип аргументов определяются функцией на C. Специальные атрибуты только для чтения:__doc__– строка документации функции илиNone, если недоступно;__name__– имя функции;__self__установлено вNone(но см. следующий пункт);__module__– имя модуля, в котором функция была определена, илиNone, если недоступно.- Встроенные методы
Это, по сути, другая форма встроенной функции, на этот раз содержащая объект, передаваемый функции на C как неявный дополнительный аргумент. Примером встроенного метода является
alist.append(), если предположить, что alist – это объект списка. В этом случае специальный атрибут только для чтения__self__устанавливается на объект, обозначенный alist.- Классы
- Классы являются вызываемыми. Обычно эти объекты выступают в роли фабрик для создания собственных экземпляров, но возможны варианты для типов классов, которые переопределяют
__new__(). Аргументы вызова передаются в__new__()и, в типичном случае, в__init__()для инициализации нового экземпляра. - Экземпляры классов
- Экземпляры произвольных классов можно сделать вызываемыми, определив в их классе метод
__call__().
- Модули
Модули – это базовая организационная единица кода Python. Они создаются системой импорта (import system), которая вызывается либо оператором
import(см.import), либо вызовом таких функций, какimportlib.import_module()и встроенной__import__(). Объект модуля имеет пространство имён, реализованное словарём (это словарь, на который ссылается атрибут__globals__функций, определённых в модуле). Обращения к атрибутам преобразуются в поиск в этом словаре, например,m.xэквивалентноm.__dict__["x"]. Объект модуля не содержит объект кода, использованный для инициализации модуля (поскольку после завершения инициализации он не нужен).Присваивание атрибуту обновляет словарь пространства имён модуля; например,
m.x = 1эквивалентноm.__dict__["x"] = 1.Специальный атрибут только для чтения:
__dict__– это пространство имён модуля в виде объекта словаря.Особенность реализации CPython: Из-за того, как CPython очищает словари модулей, словарь модуля будет очищен, когда модуль выйдет из области видимости, даже если на словарь ещё есть активные ссылки. Чтобы этого избежать, скопируйте словарь или держите модуль в памяти, пока используете его словарь напрямую.
Предопределённые (записываемые) атрибуты:
__name__– имя модуля;__doc__– строка документации модуля илиNone, если она недоступна;__file__– путь к файлу, из которого был загружен модуль, если он был загружен из файла. Атрибут__file__может отсутствовать для некоторых типов модулей, например, для модулей C, статически скомпонованных с интерпретатором; для модулей расширения, динамически загружаемых из разделяемой библиотеки, это путь к файлу разделяемой библиотеки.- Пользовательские классы
Пользовательские типы классов обычно создаются с помощью определений классов (см. раздел Определения классов). Класс имеет пространство имен, реализованное в виде объекта-словаря. Ссылки на атрибуты класса преобразуются в поиск в этом словаре, например,
C.xпреобразуется вC.__dict__["x"](хотя существует ряд хуков, которые позволяют искать атрибуты другими способами). Если имя атрибута не найдено там, поиск атрибута продолжается в базовых классах. Этот поиск в базовых классах использует порядок разрешения методов C3, который корректно работает даже при наличии структур наследования типа «ромб», где есть множественные пути наследования, ведущие к общему предку. Дополнительные сведения о C3 MRO, используемом Python, можно найти в документации, прилагаемой к выпуску 2.3, по адресу https://www.python.org/download/releases/2.3/mro/.Когда обращение к атрибуту класса (например, для класса
C) должно вернуть объект метода класса, он преобразуется в объект метода экземпляра, у которого атрибут__self__равенC. Когда оно должно вернуть объект статического метода, он преобразуется в объект, обёрнутый статическим методом. См. раздел Реализация дескрипторов о другом способе, которым атрибуты, получаемые от класса, могут отличаться от тех, что реально хранятся в его__dict__.Присваивание атрибутов класса обновляет словарь самого класса, но никогда не словарь базового класса.
Объект класса можно вызвать (см. выше), чтобы получить экземпляр класса (см. ниже).
Специальные атрибуты:
__name__– имя класса;__module__– имя модуля, в котором определён класс;__dict__– словарь, содержащий пространство имён класса;__bases__– кортеж, содержащий базовые классы в порядке их следования в списке базовых классов;__doc__– строка документации класса илиNone, если она не определена.- Экземпляры классов
Экземпляр класса создаётся вызовом объекта класса (см. выше). Экземпляр класса имеет пространство имён, реализованное как словарь, который является первым местом, где ищутся ссылки на атрибуты. Если атрибут не найден там, и класс экземпляра имеет атрибут с таким именем, поиск продолжается среди атрибутов класса. Если найден атрибут класса, являющийся объектом пользовательской функции, он преобразуется в объект метода экземпляра, чьим атрибутом
__self__является экземпляр. Объекты статического метода и метода класса также преобразуются; см. выше раздел «Классы». См. раздел Реализация дескрипторов для другого способа, которым атрибуты класса, полученные через его экземпляры, могут отличаться от объектов, фактически хранящихся в__dict__класса. Если атрибут класса не найден и у класса объекта есть метод__getattr__(), он вызывается для удовлетворения поиска.Присваивания и удаления атрибутов обновляют словарь экземпляра, но никогда не словарь класса. Если у класса есть метод
__setattr__()или__delattr__(), он вызывается вместо прямого обновления словаря экземпляра.Экземпляры классов могут вести себя как числа, последовательности или отображения, если у них есть методы с определёнными специальными именами. См. раздел Имена специальных методов.
Специальные атрибуты:
__dict__– словарь атрибутов;__class__– класс экземпляра.- Объекты ввода-вывода (также известные как файловые объекты)
Файловый объект представляет открытый файл. Существуют различные краткие способы создания файловых объектов: встроенная функция
open(), а такжеos.popen(),os.fdopen()и методmakefile()объектов сокетов (и, возможно, другие функции или методы, предоставляемые модулями расширения).Объекты
sys.stdin,sys.stdoutиsys.stderrинициализируются как файловые объекты, соответствующие стандартным потокам ввода, вывода и ошибок интерпретатора; все они открыты в текстовом режиме и поэтому следуют интерфейсу, определённому абстрактным классомio.TextIOBase.- Внутренние типы
Некоторые типы, используемые внутри интерпретатора, доступны пользователю. Их определения могут измениться в будущих версиях интерпретатора, но здесь они упомянуты для полноты.
- Объекты кода
Объекты кода представляют собой скомпилированный в байт-код исполняемый код Python, или байт-код. Разница между объектом кода и объектом функции в том, что объект функции содержит явную ссылку на глобальные переменные функции (модуль, в котором она определена), тогда как объект кода не содержит контекста; кроме того, значения аргументов по умолчанию хранятся в объекте функции, а не в объекте кода (поскольку они представляют значения, вычисляемые во время выполнения). В отличие от объектов функций, объекты кода неизменяемы и не содержат ссылок (прямых или косвенных) на изменяемые объекты.
Специальные атрибуты только для чтения:
co_name– имя функции;co_argcount– количество позиционных аргументов (включая аргументы со значениями по умолчанию);co_nlocals– количество локальных переменных, используемых функцией (включая аргументы);co_varnames– кортеж, содержащий имена локальных переменных (начиная с имён аргументов);co_cellvars– кортеж, содержащий имена локальных переменных, на которые ссылаются вложенные функции;co_freevars– кортеж, содержащий имена свободных переменных;co_code– строка, представляющая последовательность инструкций байт-кода;co_consts– кортеж, содержащий литералы, используемые байт-кодом;co_names– кортеж, содержащий имена, используемые байт-кодом;co_filename– имя файла, из которого был скомпилирован код;co_firstlineno– номер первой строки функции;co_lnotab– строка, кодирующая отображение смещений байт-кода на номера строк (подробнее см. исходный код интерпретатора);co_stacksize– требуемый размер стека (включая локальные переменные);co_flags– целое число, кодирующее набор флагов для интерпретатора.Для
co_flagsопределены следующие битовые флаги: бит0x04установлен, если функция использует синтаксис*argumentsдля принятия произвольного числа позиционных аргументов; бит0x08установлен, если функция использует синтаксис**keywordsдля принятия произвольных ключевых аргументов; бит0x20установлен, если функция является генератором.Объявления будущих возможностей (
from __future__ import division) также используют биты вco_flags, чтобы указать, был ли объект кода скомпилирован с включённой конкретной возможностью: бит0x2000установлен, если функция была скомпилирована с включённым future division; биты0x10и0x1000использовались в более ранних версиях Python.Остальные биты в
co_flagsзарезервированы для внутреннего использования.Если объект кода представляет функцию, первый элемент в
co_consts– это строка документации функции, илиNone, если она не определена.
- Объекты фреймов
Объекты фреймов представляют фреймы выполнения. Они могут встречаться в объектах трассировки стека (см. ниже).
Специальные атрибуты только для чтения:
f_backуказывает на предыдущий фрейм стека (ближе к вызывающему) илиNone, если это нижний фрейм стека;f_code– объект кода, исполняемый в этом фрейме;f_locals– словарь, используемый для поиска локальных переменных;f_globalsиспользуется для глобальных переменных;f_builtinsиспользуется для встроенных (внутренних) имён;f_lastiпредставляет точную инструкцию (это индекс в строке байт-кода объекта кода).Специальные атрибуты для записи:
f_trace, если не равенNone, – это функция, вызываемая в начале каждой строки исходного кода (используется отладчиком);f_lineno– текущий номер строки фрейма – запись в этот атрибут изнутри трассирующей функции выполняет переход на указанную строку (только для самого нижнего фрейма). Отладчик может реализовать команду Jump (также известную как Set Next Statement) путём записи в f_lineno.Объекты Frame поддерживают один метод:
-
frame.clear()¶ Этот метод очищает все ссылки на локальные переменные, хранящиеся во фрейме. Кроме того, если фрейм принадлежал генератору, генератор финализируется. Это помогает разорвать циклические ссылки с участием объектов фреймов (например, при перехвате исключения и сохранении его трассировки для дальнейшего использования).
RuntimeErrorвозбуждается, если фрейм в данный момент выполняется.Новое в версии 3.4.
-
- Объекты трассировки стека
Объекты трассировки стека представляют стек вызовов исключения. Объект трассировки создаётся при возникновении исключения. Когда поиск обработчика исключения разворачивает стек выполнения, на каждом развёрнутом уровне объект трассировки вставляется перед текущей трассировкой. При входе в обработчик исключения стек вызовов становится доступен программе. (См. раздел Оператор try). Он доступен как третий элемент кортежа, возвращаемого
sys.exc_info(). Если в программе нет подходящего обработчика, стек вызовов (красиво отформатированный) записывается в стандартный поток ошибок; если интерпретатор работает в интерактивном режиме, он также становится доступен пользователю какsys.last_traceback.Специальные атрибуты только для чтения:
tb_next– следующий уровень в трассировке стека (направление к фрейму, где произошло исключение), илиNone, если следующего уровня нет;tb_frameуказывает на фрейм выполнения текущего уровня;tb_lineno– номер строки, где произошло исключение;tb_lastiуказывает точную инструкцию. Номер строки и последняя инструкция в трассировке могут отличаться от номера строки объекта фрейма, если исключение произошло в оператореtryбез подходящего предложения except или с предложением finally.- Объекты срезов
Объекты срезов используются для представления срезов для методов
__getitem__(). Они также создаются встроенной функциейslice().Специальные атрибуты только для чтения:
start– нижняя граница;stop– верхняя граница;step– шаг (значение); каждый равенNone, если опущен. Эти атрибуты могут иметь любой тип.Объекты slice поддерживают один метод:
-
slice.indices(self, length)¶ Этот метод принимает единственный целочисленный аргумент length и вычисляет информацию о срезе, который объект среза описывал бы, если бы был применен к последовательности из length элементов. Он возвращает кортеж из трех целых чисел; соответственно это индексы start и stop, а также step или длина шага среза. Пропущенные или выходящие за границы индексы обрабатываются так же, как и для обычных срезов.
-
- Объекты статических методов
- Объекты статических методов предоставляют способ обойти преобразование объектов-функций в объекты-методы, описанное выше. Объект статического метода – это обёртка вокруг любого другого объекта, обычно определённого пользователем объекта-метода. Когда объект статического метода извлекается из класса или экземпляра класса, фактически возвращается обёрнутый объект, который не подвергается дальнейшим преобразованиям. Сами объекты статических методов не являются вызываемыми, хотя объекты, которые они оборачивают, обычно вызываемы. Объекты статических методов создаются встроенным конструктором
staticmethod(). - Объекты методов классов
- Объект метода класса, как и объект статического метода, является обёрткой вокруг другого объекта, изменяющей способ получения этого объекта из классов и экземпляров классов. Поведение объектов методов класса при таком получении описано выше, в разделе «Пользовательские методы». Объекты методов классов создаются встроенным конструктором
classmethod().
3.3. Имена специальных методов¶Special method names
Класс может реализовать определённые операции, которые вызываются специальным синтаксисом (например, арифметические операции или индексация и срезы), путём определения методов со специальными именами. Это подход Python к перегрузке операторов, позволяющий классам определять собственное поведение для языковых операторов. Например, если класс определяет метод с именем __getitem__(), а x – экземпляр этого класса, то x[i] примерно эквивалентно type(x).__getitem__(x, i). Если не указано иное, попытка выполнить операцию вызывает исключение, когда не определён подходящий метод (обычно AttributeError или TypeError).
При реализации класса, который эмулирует какой-либо встроенный тип, важно реализовывать эмуляцию только в той степени, в которой это имеет смысл для моделируемого объекта. Например, некоторые последовательности могут хорошо работать с получением отдельных элементов, но извлечение среза может не иметь смысла. (Одним из примеров этого является интерфейс NodeList в объектной модели документов W3C.)
3.3.1. Базовая настройка¶Basic customization
-
object.__new__(cls[, ...])¶ Вызывается для создания нового экземпляра класса cls.
__new__()– это статический метод (специальный случай, поэтому его не нужно объявлять таковым), который принимает в качестве первого аргумента класс, для которого запрашивается экземпляр. Остальные аргументы – это те, что были переданы в выражение конструктора объекта (вызов класса). Возвращаемое значение__new__()должно быть новым экземпляром объекта (обычно экземпляром cls).Типичные реализации создают новый экземпляр класса, вызывая метод
__new__()суперкласса с помощьюsuper().__new__(cls[, ...])с соответствующими аргументами, а затем при необходимости изменяют только что созданный экземпляр перед его возвратом.Если
__new__()возвращает экземпляр cls, то метод__init__()нового экземпляра будет вызван как__init__(self[, ...]), где self – новый экземпляр, а остальные аргументы те же, что были переданы__new__().Если
__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__()будут вызваны для объектов, которые всё ещё существуют при завершении интерпретатора.Примечание
del xне вызывает напрямуюx.__del__()– первый уменьшает счётчик ссылок наxна единицу, а второй вызывается только когда счётчик ссылокxдостигает нуля. Некоторые распространённые ситуации, которые могут помешать счётчику ссылок объекта достичь нуля, включают: циклические ссылки между объектами (например, двусвязный список или древовидная структура данных с указателями на родителя и потомка); ссылка на объект в стековом фрейме функции, перехватившей исключение (трассировка, сохранённая вsys.exc_info()[2], удерживает стековый фрейм активным); или ссылка на объект в стековом фрейме, который вызвал необработанное исключение в интерактивном режиме (трассировка, сохранённая вsys.last_traceback, удерживает стековый фрейм активным). Первая ситуация может быть исправлена только явным разрывом циклов; вторая – освобождением ссылки на объект трассировки, когда он больше не нужен; третья – сохранениемNoneвsys.last_traceback. Циклические ссылки, которые стали мусором, обнаруживаются и очищаются, если включён циклический сборщик мусора (включён по умолчанию). Обратитесь к документации модуляgcдля получения дополнительной информации по этой теме.Предупреждение
Из-за непредсказуемых обстоятельств, при которых вызываются методы
__del__(), исключения, возникающие во время их выполнения, игнорируются, а вместо этого вsys.stderrвыводится предупреждение. Кроме того, когда__del__()вызывается в ответ на удаление модуля (например, при завершении программы), другие глобальные переменные, на которые ссылается метод__del__(), могут уже быть удалены или находиться в процессе удаления (например, механизм импорта завершает работу). По этой причине методы__del__()должны делать абсолютный минимум, необходимый для поддержания внешних инвариантов. Начиная с версии 1.5, 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()классаstr) для получения «отформатированного» строкового представления объекта. Аргументformat_spec– это строка, содержащая описание желаемых параметров форматирования. Интерпретация аргументаformat_specзависит от типа, реализующего__format__(), однако большинство классов либо делегируют форматирование одному из встроенных типов, либо используют аналогичный синтаксис параметров форматирования.См. мини-язык спецификации формата для описания стандартного синтаксиса форматирования.
Возвращаемое значение должно быть строковым объектом.
Изменено в версии 3.4: Метод __format__ самого
objectвызываетTypeError, если ему передана непустая строка.
-
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()для этого значения, чтобы определить, истинно оно или ложно.По умолчанию
__ne__()делегирует полномочия__eq__()и инвертирует результат, если только он не равенNotImplemented. Между операторами сравнения нет других неявных связей: например, истинность(x<y or x==y)не влечётx<=y. Для автоматической генерации операций упорядочивания из одной корневой операции см.functools.total_ordering().Важные замечания по созданию хешируемых объектов, поддерживающих пользовательские операции сравнения и пригодных для использования в качестве ключей словаря, см. в параграфе
__hash__().Не существует версий этих методов с переставленными аргументами (которые используются, когда левый аргумент не поддерживает операцию, а правый поддерживает); скорее,
__lt__()и__gt__()являются отражением друг друга,__le__()и__ge__()являются отражением друг друга, а__eq__()и__ne__()являются собственным отражением. Если операнды разных типов и тип правого операнда является прямым или косвенным подклассом типа левого операнда, то отражённый метод правого операнда имеет приоритет, в противном случае приоритет имеет метод левого операнда. Виртуальное подклассирование не учитывается.
-
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.Hashable).Если класс, переопределяющий
__eq__(), должен сохранить реализацию__hash__()от родительского класса, интерпретатору необходимо явно сообщить об этом, установив__hash__ = <ParentClass>.__hash__.Если класс, который не переопределяет
__eq__(), хочет отключить поддержку хеширования, он должен включить__hash__ = Noneв определение класса. Класс, определяющий собственный__hash__(), который явно вызываетTypeError, будет ошибочно идентифицирован как хешируемый при вызовеisinstance(obj, collections.Hashable).Примечание
По умолчанию значения
__hash__()объектов str, bytes и datetime «солятся» непредсказуемым случайным значением. Хотя они остаются постоянными в рамках одного процесса Python, их нельзя предсказать при повторных запусках Python.Это предназначено для защиты от отказа в обслуживании, вызванного специально подобранными входными данными, которые используют наихудшую производительность вставки в dict (сложность O(n^2)). Подробнее см. на http://www.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. Настройка доступа к атрибутам¶Customizing attribute access
Следующие методы могут быть определены для настройки смысла доступа к атрибутам (чтения, присваивания или удаления x.name) для экземпляров классов.
-
object.__getattr__(self, name)¶ Вызывается, когда поиск атрибута не обнаружил атрибут в обычных местах (т.е. он не является атрибутом экземпляра и не найден в дереве классов для
self).name– имя атрибута. Этот метод должен вернуть (вычисленное) значение атрибута или вызвать исключениеAttributeError.Обратите внимание, если атрибут найден через обычный механизм,
__getattr__()не вызывается. (Это намеренная асимметрия между__getattr__()и__setattr__().) Это сделано как из соображений эффективности, так и потому, что в противном случае__getattr__()не имел бы способа получить доступ к другим атрибутам экземпляра. Обратите также внимание, что, по крайней мере, для переменных экземпляра можно имитировать полный контроль, не вставляя никаких значений в словарь атрибутов экземпляра (а вместо этого вставляя их в другой объект). См. метод__getattribute__()ниже для способа действительно получить полный контроль над доступом к атрибутам.
-
object.__getattribute__(self, name)¶ Вызывается безусловно для реализации доступа к атрибутам экземпляров класса. Если класс также определяет
__getattr__(), последний не будет вызван, пока__getattribute__()либо не вызовет его явно, либо не вызоветAttributeError. Этот метод должен возвращать (вычисленное) значение атрибута или вызывать исключениеAttributeError. Чтобы избежать бесконечной рекурсии в этом методе, его реализация всегда должна вызывать метод базового класса с тем же именем для доступа к любым необходимым атрибутам, например,object.__getattribute__(self, name).Примечание
Этот метод всё равно может быть обойдён при поиске специальных методов в результате неявного вызова через синтаксис языка или встроенные функции. См. Поиск специальных методов.
-
object.__setattr__(self, name, value)¶ Вызывается при попытке присвоения атрибута. Этот метод вызывается вместо обычного механизма (т.е. сохранения значения в словаре экземпляра). name – имя атрибута, value – значение, которое ему присваивается.
Если
__setattr__()хочет присвоить значение атрибуту экземпляра, он должен вызвать метод базового класса с тем же именем, например,object.__setattr__(self, name, value).
-
object.__delattr__(self, name)¶ Как
__setattr__(), но для удаления атрибутов вместо присваивания. Этот метод следует реализовывать, только еслиdel obj.nameимеет смысл для объекта.
-
object.__dir__(self)¶ Вызывается, когда для объекта вызывается
dir(). Должна быть возвращена последовательность.dir()преобразует возвращённую последовательность в список и сортирует его.
3.3.2.1. Реализация дескрипторов¶Implementing Descriptors
Следующие методы применяются только когда экземпляр класса, содержащего
метод (так называемого класса-дескриптора), присутствует в классе-владельце (дескриптор
должен быть либо в словаре класса владельца, либо в словаре класса
одного из его родителей). В приведённых ниже примерах «атрибут»
относится к атрибуту, имя которого является ключом свойства в словаре
__dict__ класса-владельца.
-
object.__get__(self, instance, owner)¶ Вызывается для получения атрибута класса-владельца (доступ к атрибуту класса) или экземпляра этого класса (доступ к атрибуту экземпляра). owner всегда является классом-владельцем, а instance – это экземпляр, через который был получен доступ к атрибуту, или
None, когда доступ к атрибуту осуществляется через owner. Этот метод должен возвращать (вычисленное) значение атрибута или вызывать исключениеAttributeError.
-
object.__set__(self, instance, value)¶ Вызывается для установки атрибута экземпляра instance класса-владельца в новое значение value.
-
object.__delete__(self, instance)¶ Вызывается для удаления атрибута экземпляра instance класса-владельца.
Атрибут __objclass__ интерпретируется модулем inspect как указание класса, в котором был определён этот объект (правильная установка может помочь при интроспекции динамических атрибутов класса во время выполнения). Для вызываемых объектов он может указывать, что в качестве первого позиционного аргумента ожидается или требуется экземпляр указанного типа (или подкласса) (например, CPython устанавливает этот атрибут для несвязанных методов, реализованных на C).
3.3.2.2. Вызов дескрипторов¶Invoking Descriptors
В общем, дескриптор – это атрибут объекта с «поведением связывания», доступ к атрибуту которого переопределён методами протокола дескриптора: __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
- Если
aявляется экземпляромsuper, то связываниеsuper(B, obj).m()выполняет поиск вobj.__class__.__mro__базового классаA, непосредственно предшествующегоB, а затем вызывает дескриптор с помощью вызова:A.__dict__['m'].__get__(obj, obj.__class__).
Для привязки к экземплярам приоритет вызова дескриптора зависит от того, какие методы дескриптора определены. Дескриптор может определять любую комбинацию __get__(), __set__() и __delete__(). Если он не определяет __get__(), то при обращении к атрибуту будет возвращён сам объект дескриптора, если только в словаре экземпляра нет соответствующего значения. Если дескриптор определяет __set__() и/или __delete__(), это дескриптор данных; если не определяет ни того, ни другого – это дескриптор не-данных. Обычно дескрипторы данных определяют и __get__(), и __set__(), а дескрипторы не-данных – только метод __get__(). Дескрипторы данных с определёнными __set__() и __get__() всегда переопределяют переопределение в словаре экземпляра. В отличие от них, дескрипторы не-данных могут быть переопределены экземплярами.
Методы Python (включая staticmethod() и classmethod()) реализованы как дескрипторы без данных. Соответственно, экземпляры могут переопределять и заменять методы. Это позволяет отдельным экземплярам приобретать поведение, отличное от других экземпляров того же класса.
Функция property() реализована как дескриптор данных. Соответственно, экземпляры не могут переопределить поведение свойства.
3.3.2.3. __slots__¶
По умолчанию экземпляры классов имеют словарь для хранения атрибутов. Это расходует память для объектов с очень небольшим количеством переменных экземпляра. Расход памяти может стать критическим при создании большого числа экземпляров.
Поведение по умолчанию можно переопределить, определив __slots__ в определении класса. Объявление __slots__ принимает последовательность переменных экземпляра и резервирует ровно столько памяти в каждом экземпляре, чтобы хранить значение для каждой переменной. Память экономится, поскольку __dict__ не создаётся для каждого экземпляра.
-
object.__slots__¶ Этой переменной класса можно присвоить строку, итерируемый объект или последовательность строк с именами переменных, используемых экземплярами. __slots__ резервирует место для объявленных переменных и предотвращает автоматическое создание __dict__ и __weakref__ для каждого экземпляра.
3.3.2.3.1. Примечания по использованию __slots__¶Notes on using __slots__
- При наследовании от класса без __slots__ атрибут __dict__ этого класса всегда будет доступен, поэтому определение __slots__ в подклассе не имеет смысла.
- Без переменной __dict__ экземплярам нельзя присваивать новые переменные, не перечисленные в определении __slots__. Попытки присвоить имя переменной, не указанной в списке, вызывают
AttributeError. Если требуется динамическое присваивание новых переменных, добавьте'__dict__'в последовательность строк в объявлении __slots__. - Без переменной __weakref__ для каждого экземпляра классы, определяющие __slots__, не поддерживают слабые ссылки на свои экземпляры. Если требуется поддержка слабых ссылок, добавьте
'__weakref__'в последовательность строк в объявлении __slots__. - __slots__ реализуются на уровне класса путём создания дескрипторов (Реализация дескрипторов) для каждого имени переменной. В результате атрибуты класса нельзя использовать для установки значений по умолчанию для переменных экземпляра, определённых __slots__; в противном случае атрибут класса перезаписал бы присваивание дескриптора.
- Действие объявления __slots__ ограничено классом, в котором оно определено. В результате подклассы будут иметь __dict__, если только они также не определят __slots__ (который должен содержать только имена дополнительных слотов).
- Если класс определяет слот, который также определён в базовом классе, переменная экземпляра, определённая слотом базового класса, становится недоступной (за исключением прямого получения её дескриптора из базового класса). Это делает поведение программы неопределённым. В будущем может быть добавлена проверка для предотвращения такой ситуации.
- Непустой __slots__ не работает для классов, производных от встроенных типов «переменной длины»,
таких как
int,bytesиtuple. - Любому итерируемому объекту, не являющемуся строкой, может быть присвоено __slots__. Также могут использоваться отображения; однако в будущем значениям, соответствующим каждому ключу, может быть присвоен особый смысл.
- Присваивание __class__ работает, только если оба класса имеют одинаковые __slots__.
3.3.3. Настройка создания классов¶Customizing class creation
По умолчанию классы создаются с помощью type(). Тело класса
выполняется в новом пространстве имён, а имя класса локально привязывается к
результату type(name, bases, namespace).
Процесс создания класса можно настроить, передав metaclass
ключевой аргумент в строке определения класса или унаследовавшись от
существующего класса, который содержит такой аргумент. В следующем примере
как MyClass, так и MySubclass являются экземплярами Meta:
class Meta(type):
pass
class MyClass(metaclass=Meta):
pass
class MySubclass(MyClass):
pass
Любые другие ключевые аргументы, указанные в определении класса, передаются всем операциям метакласса, описанным ниже.
При выполнении определения класса происходят следующие шаги:
- Определяется подходящий метакласс.
- Подготавливается пространство имён класса.
- Выполняется тело класса.
- Создаётся объект класса.
3.3.3.1. Определение подходящего метакласса¶Determining the appropriate metaclass
Подходящий метакласс для определения класса выбирается следующим образом:
- Если не указаны базовые классы и явный метакласс, то используется
type(). - Если указан явный метакласс и он не является экземпляром
type(), то он используется напрямую в качестве метакласса. - Если в качестве явного метакласса указан экземпляр
type()или определены базовые классы, то используется наиболее производный метакласс.
Наиболее производный метакласс выбирается из явно указанного
метакласса (если есть) и метаклассов (т.е. type(cls)) всех указанных
базовых классов. Наиболее производный метакласс – это такой метакласс, который является подтипом всех
этих кандидатов. Если ни один из кандидатов не удовлетворяет
этому критерию, то определение класса завершится ошибкой TypeError.
3.3.3.2. Подготовка пространства имён класса¶Preparing the class namespace
После того как подходящий метакласс определён, подготавливается пространство
имён класса. Если у метакласса есть атрибут __prepare__, то он вызывается
как namespace = metaclass.__prepare__(name, bases, **kwds) (дополнительные
именованные аргументы, если они есть, берутся из определения класса).
Если у метакласса нет атрибута __prepare__, то пространство имён класса
инициализируется как пустой экземпляр dict().
См. также
- PEP 3115 – Метаклассы в Python 3000
- Ввёл перехватчик пространства имён
__prepare__
3.3.3.3. Выполнение тела класса¶Executing the class body
Тело класса выполняется (приблизительно) как
exec(body, globals(), namespace). Ключевое отличие от обычного
вызова exec() заключается в том, что лексическая область видимости позволяет телу класса (включая
любые методы) ссылаться на имена из текущей и внешних областей видимости, когда
определение класса находится внутри функции.
Однако, даже если определение класса находится внутри функции, методы, определённые внутри класса, всё равно не могут видеть имена, определённые в области видимости класса. Переменные класса должны быть доступны через первый параметр методов экземпляра или класса, и совсем недоступны из статических методов.
3.3.3.4. Создание объекта класса¶Creating the class object
После заполнения пространства имён класса путём выполнения тела класса
объект класса создаётся вызовом
metaclass(name, bases, namespace, **kwds) (дополнительные ключевые аргументы,
переданные здесь, те же, что и переданные в __prepare__).
Этот объект класса – тот самый, на который будет ссылаться форма
без аргументов super(). __class__ – это неявная ссылка на замыкание,
создаваемая компилятором, если какой-либо метод в теле класса обращается к
__class__ или super. Благодаря этому форма без аргументов
super() может корректно определить определяемый класс, исходя из
лексической области видимости, а класс или экземпляр, использованный для текущего
вызова, определяется по первому аргументу, переданному методу.
После создания объекта класса он передаётся декораторам класса,\указанным в определении класса (если они есть), и полученный объект связывается в локальном пространстве имён как определённый класс.
Когда новый класс создаётся с помощью type.__new__, объект, переданный в качестве
параметра namespace, копируется в стандартный словарь Python, а исходный
объект отбрасывается. Новая копия становится атрибутом __dict__
объекта класса.
См. также
- PEP 3135 – Новый super
- Описывает неявную ссылку на замыкание
__class__
3.3.3.5. Пример метакласса¶Metaclass example
Потенциальные возможности использования метаклассов безграничны. Некоторые идеи, которые были исследованы, включают логирование, проверку интерфейсов, автоматическое делегирование, автоматическое создание свойств, прокси, фреймворки, а также автоматическую блокировку/синхронизацию ресурсов.
Вот пример метакласса, использующего collections.OrderedDict
для запоминания порядка определения переменных класса:
class OrderedClass(type):
@classmethod
def __prepare__(metacls, name, bases, **kwds):
return collections.OrderedDict()
def __new__(cls, name, bases, namespace, **kwds):
result = type.__new__(cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
class A(metaclass=OrderedClass):
def one(self): pass
def two(self): pass
def three(self): pass
def four(self): pass
>>> A.members
('__module__', 'one', 'two', 'three', 'four')
Когда выполняется определение класса A, процесс начинается с
вызова метода метакласса __prepare__(), который возвращает пустой
collections.OrderedDict. Это отображение записывает методы и
атрибуты A по мере их определения в теле оператора class.
После выполнения этих определений упорядоченный словарь полностью заполняется
и вызывается метод метакласса __new__(). Этот метод строит
новый тип и сохраняет ключи упорядоченного словаря в атрибут с
именем members.
3.3.4. Настройка проверок экземпляров и подклассов¶Customizing instance and subclass checks
Следующие методы используются для переопределения поведения по умолчанию
встроенных функций isinstance() и issubclass().
В частности, метакласс abc.ABCMeta реализует эти методы,\чтобы позволить добавлять абстрактные базовые классы (ABC) как «виртуальные базовые
классы» к любому классу или типу (включая встроенные типы), в том числе к другим
ABC.
-
class.__instancecheck__(self, instance)¶ Возвращает истину, если instance должен считаться (прямым или косвенным) экземпляром class. Если определён, вызывается для реализации
isinstance(instance, class).
-
class.__subclasscheck__(self, subclass)¶ Возвращает истину, если subclass должен считаться (прямым или косвенным) подклассом class. Если определён, вызывается для реализации
issubclass(subclass, class).
Обратите внимание, что эти методы ищутся на типе (метаклассе) класса. Их нельзя определить как методы класса в самом классе. Это согласуется с поиском специальных методов, которые вызываются на экземплярах, только в данном случае экземпляром является сам класс.
См. также
- PEP 3119 – Введение абстрактных базовых классов
- Содержит спецификацию настройки поведения
isinstance()иissubclass()через__instancecheck__()и__subclasscheck__(), с обоснованием этой функциональности в контексте добавления абстрактных базовых классов (см. модульabc) в язык.
3.3.5. Эмуляция вызываемых объектов¶Emulating callable objects
-
object.__call__(self[, args...])¶ Вызывается, когда экземпляр «вызывается» как функция; если этот метод определён,
x(arg1, arg2, ...)является сокращённой формой дляx.__call__(arg1, arg2, ...).
3.3.6. Эмуляция типов-контейнеров¶Emulating container types
Следующие методы могут быть определены для реализации контейнерных объектов. Контейнеры
обычно представляют собой последовательности (например, списки или кортежи) или отображения (например, словари),
но могут также представлять другие контейнеры. Первый набор методов используется
для эмуляции последовательности или отображения; различие в том, что для
последовательности допустимыми ключами должны быть целые числа k, для которых 0 <= k <
N, где N – длина последовательности, или объекты срезов, определяющие диапазон элементов. Также рекомендуется, чтобы отображения предоставляли методы
keys(), values(), items(), get(), clear(),
setdefault(), pop(), popitem(), copy() и
update(), поведение которых аналогично соответствующим методам стандартных словарей Python. Модуль collections предоставляет
абстрактный базовый класс MutableMapping,
помогающий создать эти методы на основе базового набора
__getitem__(), __setitem__(), __delitem__() и keys().
Изменяемые последовательности должны предоставлять методы append(), count(),
index(), extend(), insert(), pop(), remove(),
reverse() и sort(), как стандартные списки Python. Наконец,
типы последовательностей должны реализовывать сложение (означающее конкатенацию) и
умножение (означающее повторение) путём определения методов __add__(),
__radd__(), __iadd__(), __mul__(), __rmul__() и
__imul__(), описанных ниже; они не должны определять другие числовые
операторы. Рекомендуется, чтобы и отображения, и последовательности реализовывали
метод __contains__() для эффективного использования оператора in; для
отображений in должен искать по ключам отображения; для последовательностей –
по значениям. Также рекомендуется, чтобы и отображения, и последовательности
реализовывали метод __iter__() для эффективной итерации по контейнеру; для отображений
__iter__() должен быть тем же, что и keys(); для последовательностей он должен
итерировать по значениям.
-
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. Этот метод предназначен исключительно для оптимизации и никогда не требуется для корректности.Новое в версии 3.4.
Примечание
Срез выполняется исключительно с помощью следующих трёх методов. Вызов вида
a[1:2] = b
преобразуется в
a[slice(1, 2, None)] = b
и так далее. Отсутствующие элементы среза всегда заполняются значением None.
-
object.__getitem__(self, key)¶ Вызывается для реализации вычисления
self[key]. Для последовательностей, допустимыми ключами должны быть целые числа и срезы. Обратите внимание, что особая интерпретация отрицательных индексов (если класс хочет имитировать последовательность типа) возлагается на метод__getitem__(). Если key имеет неподходящий тип, может быть возбужденоTypeError; если значение выходит за пределы множества индексов для последовательности (после любой специальной интерпретации отрицательных значений), следует возбудитьIndexError. Для отображений, если key отсутствует (не в контейнере), следует возбудитьKeyError.Примечание
forожидают, что для недопустимых индексов будет возбужденоIndexError, чтобы обеспечить правильное обнаружение конца последовательности.
-
object.__missing__(self, key)¶ Вызывается методом
dict.__getitem__()для реализацииself[key]в подклассах dict, когда ключ отсутствует в словаре.
-
object.__setitem__(self, key, value)¶ Вызывается для реализации присваивания
self[key]. То же примечание, что и для__getitem__(). Этот метод следует реализовывать только для отображений, если объекты поддерживают изменение значений по ключам или добавление новых ключей, или для последовательностей, если элементы можно заменять. Те же исключения должны возбуждаться для неправильных значений ключа, что и для метода__getitem__().
-
object.__delitem__(self, key)¶ Вызывается для реализации удаления
self[key]. То же примечание, что и для__getitem__(). Этот метод следует реализовывать только для отображений, если объекты поддерживают удаление ключей, или для последовательностей, если элементы можно удалять из последовательности. Те же исключения должны возбуждаться для неправильных ключа значений, что и для метода__getitem__().
-
object.__iter__(self)¶ Этот метод вызывается, когда для контейнера требуется итератор. Этот метод должен возвращать новый объект-итератор, который может перебирать все объекты в контейнере. Для отображений он должен перебирать ключи контейнера.
Объекты-итераторы также должны реализовывать этот метод; они обязаны возвращать самих себя. Для получения дополнительной информации об объектах-итераторах см. Типы итераторов.
-
object.__reversed__(self)¶ Вызывается (если определён) встроенной функцией
reversed()для реализации обратной итерации. Должен возвращать новый объект-итератор, который перебирает все объекты в контейнере в обратном порядке.Если метод
__reversed__()не определён, встроенная функцияreversed()будет использовать протокол последовательности (__len__()и__getitem__()). Объекты, поддерживающие протокол последовательности, должны определять__reversed__()только в том случае, если могут предоставить реализацию, которая эффективнее, чем предоставленнаяreversed().
Операторы проверки принадлежности (in и not in) обычно реализуются как итерация по последовательности. Однако объекты-контейнеры могут предоставить следующий специальный метод с более эффективной реализацией, которая также не требует, чтобы объект был последовательностью.
-
object.__contains__(self, item)¶ Вызывается для реализации операторов проверки вхождения. Должен возвращать true, если элемент находится в self, и false в противном случае. Для объектов-отображений следует учитывать ключи отображения, а не значения или пары ключ-значение.
Для объектов, которые не определяют
__contains__(), проверка вхождения сначала пытается выполнить итерацию через__iter__(), затем старый протокол итерации последовательностей через__getitem__(); см. этот раздел в справочнике по языку.
3.3.7. Эмуляция числовых типов¶Emulating numeric types
Следующие методы можно определить для эмуляции числовых объектов. Методы, соответствующие операциям, которые не поддерживаются конкретным типом реализуемого числа (например, побитовые операции для нецелых чисел), следует оставить неопределёнными.
-
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__(), вызываетсяx.__add__(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)¶ -
object.__rlshift__(self, other)¶ -
object.__rrshift__(self, other)¶ -
object.__rand__(self, other)¶ -
object.__rxor__(self, other)¶ -
object.__ror__(self, other)¶ Эти методы вызываются для реализации бинарных арифметических операций (
+,-,*,@,/,//,%,divmod(),pow(),**,<<,>>,&,^,|) с переставленными (отражёнными) операндами. Эти функции вызываются только в том случае, если левый операнд не поддерживает соответствующую операцию и операнды относятся к разным типам. [2] Например, для вычисления выраженияx - y, где y – это экземпляр класса, у которого есть метод__rsub__(),y.__rsub__(x)вызывается, еслиx.__sub__(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). Если конкретный метод не определён, составное присваивание сводится к обычным методам. Например, если x является экземпляром класса с методом__iadd__(), тоx += yэквивалентноx = x.__iadd__(y). В противном случае рассматриваются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)¶ -
object.__round__(self[, n])¶ Вызывается для реализации встроенных функций
complex(),int(),float()иround(). Должен возвращать значение соответствующего типа.
-
object.__index__(self)¶ Вызывается для реализации
operator.index(), а также всякий раз, когда Python необходимо без потерь преобразовать числовой объект в целое число (например, при срезе или во встроенных функцияхbin(),hex()иoct()). Наличие этого метода указывает, что числовой объект является целочисленным типом. Должен возвращать целое число.Примечание
Чтобы обеспечить целостность класса целочисленного типа, вместе с
__index__()следует также определять__int__(), и оба метода должны возвращать одно и то же значение.
3.3.8. Контекстные менеджеры оператора with¶With Statement Context Managers
Контекстный менеджер – это объект, который определяет контекст выполнения, устанавливаемый
при выполнении оператора with. Контекстный менеджер
обрабатывает вход в требуемый контекст выполнения и выход из него для
выполнения блока кода. Контекстные менеджеры обычно вызываются с помощью
оператора with (описанного в разделе Оператор with), но также могут
использоваться прямым вызовом их методов.
Типичные случаи использования контекстных менеджеров включают сохранение и восстановление различных видов глобального состояния, блокировку и разблокировку ресурсов, закрытие открытых файлов и т.д.
Для получения дополнительной информации о контекстных менеджерах см. Типы контекстных менеджеров.
-
object.__enter__(self)¶ Входит в контекст выполнения, связанный с этим объектом. Оператор
withпривязывает возвращаемое значение этого метода к цели(ям), указанным в предложенииasэтого оператора, если таковые имеются.
-
object.__exit__(self, exc_type, exc_value, traceback)¶ Выходит из контекста выполнения, связанного с этим объектом. Параметры описывают исключение, которое привело к выходу из контекста. Если контекст был завершён без исключения, все три аргумента будут
None.Если передано исключение и метод хочет подавить его (т.е. предотвратить его распространение), он должен вернуть истинное значение. В противном случае исключение будет обработано обычным образом при выходе из этого метода.
Обратите внимание, что методы
__exit__()не должны повторно возбуждать переданное исключение; это ответственность вызывающего кода.
3.3.9. Поиск специальных методов¶Special method lookup
Для пользовательских классов неявные вызовы специальных методов гарантированно работают корректно только в том случае, если они определены в типе объекта, а не в словаре экземпляра объекта. Это поведение является причиной того, что следующий код вызывает исключение:
>>> 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__() # Явный поиск через экземпляр
Class getattribute invoked
10
>>> type(c).__len__(c) # Явный поиск через тип
Metaclass getattribute invoked
10
>>> len(c) # Неявный поиск
10
Обход механизма __getattribute__() таким образом даёт значительную возможность для оптимизации скорости в интерпретаторе, ценой некоторой гибкости в обработке специальных методов (специальный метод должен быть установлен на самом объекте класса, чтобы интерпретатор мог его последовательно вызывать).
3.4. Корутины¶Coroutines
3.4.1. Ожидаемые объекты¶Awaitable Objects
Объект ожидаемый объект обычно реализует метод __await__().
Объекты корутина, возвращаемые функциями async def, являются ожидаемыми.
Примечание
Объекты итератора генератора, возвращаемые из генераторов,
декорированных с помощью types.coroutine() или asyncio.coroutine(),
также являются ожидаемыми, но не реализуют __await__().
-
object.__await__(self)¶ Должен возвращать итератор. Следует использовать для реализации объектов ожидаемых. Например,
asyncio.Futureреализует этот метод для совместимости с выражениемawait.
Новое в версии 3.5.
См. также
PEP 492 для получения дополнительной информации об ожидаемых объектах.
3.4.2. Объекты корутин¶Coroutine Objects
Объекты корутина являются объектами ожидаемый.
Выполнение корутины можно контролировать, вызывая __await__() и итерируя результат. Когда корутина завершает выполнение и возвращает значение, итератор возбуждает StopIteration, а атрибут value исключения содержит возвращаемое значение. Если корутина возбуждает исключение, оно распространяется итератором. Корутины не должны напрямую возбуждать необработанные исключения StopIteration.
Корутины также имеют методы, перечисленные ниже, которые аналогичны методам генераторов (см. Методы итератора генератора). Однако, в отличие от генераторов, корутины напрямую не поддерживают итерацию.
Изменено в версии 3.5.2: Ожидание корутины более одного раза является RuntimeError.
-
coroutine.send(value)¶ Запускает или возобновляет выполнение корутины. Если value равно
None, это эквивалентно продвижению итератора, возвращаемого__await__(). Если value не равноNone, этот метод делегирует методуsend()итератора, который вызвал приостановку корутины. Результат (возвращаемое значение,StopIterationили другое исключение) такой же, как при итерации по возвращаемому значению__await__(), описанной выше.
-
coroutine.throw(type[, value[, traceback]])¶ Возбуждает указанное исключение в корутине. Этот метод делегирует методу
throw()итератора, который вызвал приостановку корутины, если у него есть такой метод. В противном случае исключение возбуждается в точке приостановки. Результат (возвращаемое значение,StopIterationили другое исключение) такой же, как при итерации по возвращаемому значению__await__(), описанной выше. Если исключение не перехвачено в корутине, оно распространяется обратно к вызывающему.
-
coroutine.close()¶ Заставляет корутину выполнить очистку и завершиться. Если корутина приостановлена, этот метод сначала делегирует методу
close()итератора, который вызвал приостановку корутины, если у него есть такой метод. Затем он возбуждаетGeneratorExitв точке приостановки, заставляя корутину немедленно выполнить очистку. Наконец, корутина помечается как завершившая выполнение, даже если она никогда не была запущена.Объекты корутин автоматически закрываются с помощью описанного выше процесса, когда они собираются быть уничтоженными.
3.4.3. Асинхронные итераторы¶Asynchronous Iterators
Асинхронный итерируемый объект может вызывать асинхронный код в своей
__aiter__ реализации, а асинхронный итератор может вызывать асинхронный код в своем __anext__ методе.
Асинхронные итераторы можно использовать в операторе async for.
-
object.__aiter__(self)¶ Должен возвращать объект асинхронный итератор.
-
object.__anext__(self)¶ Должен возвращать ожидаемый объект, который даёт следующее значение итератора. Должен возбуждать ошибку
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.
Примечание
Changed in version 3.5.2: Starting with CPython 3.5.2, __aiter__ can directly return
asynchronous iterators. Returning
an awaitable object will result in a
PendingDeprecationWarning.
Рекомендуемый способ написания обратно совместимого кода в
CPython 3.5.x – продолжать возвращать ожидаемые объекты из
__aiter__. Чтобы избежать PendingDeprecationWarning
и сохранить обратную совместимость, можно использовать следующий
декоратор:
import functools
import sys
if sys.version_info < (3, 5, 2):
def aiter_compat(func):
@functools.wraps(func)
async def wrapper(self):
return func(self)
return wrapper
else:
def aiter_compat(func):
return func
Пример:
class AsyncIterator:
@aiter_compat
def __aiter__(self):
return self
async def __anext__(self):
...
Начиная с CPython 3.6, PendingDeprecationWarning
будет заменён на DeprecationWarning.
В CPython 3.7 возврат ожидаемого объекта из __aiter__ приведёт
к RuntimeError.
3.4.4. Асинхронные контекстные менеджеры¶Asynchronous Context Managers
Асинхронный менеджер контекста – это менеджер контекста, способный
приостанавливать выполнение в своих методах __aenter__ и __aexit__.
Асинхронные менеджеры контекста можно использовать в инструкции async with.
-
object.__aenter__(self)¶ Этот метод семантически похож на
__enter__(), с той лишь разницей, что он должен возвращать ожидаемый объект.
-
object.__aexit__(self, exc_type, exc_value, traceback)¶ Этот метод семантически похож на
__exit__(), с той лишь разницей, что он должен возвращать ожидаемый объект.
Пример класса асинхронного менеджера контекста:
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] | It is possible in some cases to change an object’s type, under certain controlled conditions. It generally isn’t a good idea though, since it can lead to some very strange behaviour if it is handled incorrectly. |
| [2] | Для операндов одного типа предполагается, что если неотражённый метод (например, __add__()) завершается неудачей, операция не поддерживается, поэтому отражённый метод не вызывается. |