Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Внутри CPython гид по интерпретатору Python.pdf
Скачиваний:
6
Добавлен:
07.04.2024
Размер:
8.59 Mб
Скачать

264    Объекты и типы

Тип PyVarObject расширяет PyObject, добавляя следующие поля:

ПОЛЕ

ТИП

НАЗНАЧЕНИЕ

ob_base

PyObject

Базовый тип

ob_size

Py_ssize_t

Количество содержащихся элементов

Например, объявление типа int PyLongObject — выглядит так:

struct _longobject {

PyObject_VAR_HEAD digit ob_digit[1]; }; /* PyLongObject */

ТИП TYPE

В Python объекты содержат свойство ob_type. Для получения его значения можно воспользоваться встроенной функцией type():

>>>t = type("hello")

>>>t

<class 'str'>

Результатом type() является экземпляр PyTypeObject:

>>> type(t) <class 'type'>

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

Например, объекты всегда реализуют метод __repr__():

>>>class example:

... x = 1

>>>i = example()

>>>repr(i)

'<__main__.example object at 0x10b418100>'

Реализация __repr__() всегда располагается по одному адресу в определении типа каждого объекта. Эта позиция называется слотом типа.

Книги для программистов: https://t.me/booksforits

Тип type    265

Слоты типов

Все слоты типов определяются в Include cpython object.h.

Каждый слот типа характеризуется именем свойства и сигнатурой функции. Например, функция __repr__() называется tp_repr и имеет сигнатуру reprfunc:

struct PyTypeObject

---

typedef struct _typeobject {

...

reprfunc tp_repr;

...

} PyTypeObject;

Сигнатура reprfunc определяется в Include cpython object.h как имеющая один аргумент PyObject* (self):

typedef PyObject *(*reprfunc)(PyObject *);

А cellobject реализует слот tp_repr при помощи функции cell_repr:

PyTypeObject PyCell_Type = {

PyVarObject_HEAD_INIT(&PyType_Type, 0)

"cell",

sizeof(PyCellObject),

 

0,

 

(destructor)cell_dealloc,

/* tp_dealloc */

0,

/* tp_vectorcall_offset */

0,

/* tp_getattr */

0,

/* tp_setattr */

0,

/* tp_as_async */

(reprfunc)cell_repr,

/* tp_repr */

...

 

};

 

Кроме слотов PyTypeObject, обозначаемых префиксом tp_, существуют и другие определения слотов типов:

СЛОТ ТИПА

ПРЕФИКС

PyNumberMethods

nb_

PySequenceMethods

sq_

Книги для программистов: https://t.me/booksforits

266    Объекты и типы

СЛОТ ТИПА

ПРЕФИКС

PyMappingMethods

mp_

PyAsyncMethods

am_

PyBufferProcs

bf_

Каждому слоту типа назначается уникальный номер, определяемый в Include typeslots.h. При обращении к слоту типа в объекте следует использовать эти константы.

Например, tp_repr имеет постоянную позицию 66, а константа Py_tp_repr всегда соответствует позиции слота типа. Эти константы полезны для проверки того, реализует ли объект конкретную функцию слота типа.

Работа с типами в C

В модулях расширения C и коде CPython вам придется часто работать с типом PyObject*.

Например, при выполнении x[n] для объекта, поддерживающего индексирование (такого, как список или строка), будет вызвана функция PyObject_ GetItem(), которая обратится к объекту x для определения того, как он должен индексироваться:

Objects abstract.c, строка 146

PyObject *

PyObject_GetItem(PyObject *o, PyObject *key)

{

PyMappingMethods *m; PySequenceMethods *ms;

...

PyObject_GetItem() подходит как для типов отображений (например, сло­ варей), так и для типов последовательностей (например, списков и кортежей).

Если экземпляр o содержит методы последовательностей, то o->ob_type- >tp_as_sequence дает значение true. Кроме того, если в экземпляре определена функция слота sq_item, предполагается, что он правильно реализует протокол последовательности.

Книги для программистов: https://t.me/booksforits

Тип type    267

Значение key вычисляется для проверки того, является ли оно целым числом, и элемент запрашивается из объекта последовательности вызовом

PySequence_GetItem():

ms = o->ob_type->tp_as_sequence; if (ms && ms->sq_item) {

if (PyIndex_Check(key)) { Py_ssize_t key_value;

key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred())

return NULL;

return PySequence_GetItem(o, key_value);

}

else {

return type_error("sequence index must "

"be integer, not '%.200s'", key);

}

}

Словари свойств типов

Python поддерживает определение новых типов с ключевым словом class. Типы, определяемые пользователем, создаются вызовом type_new() в модуле объекта типа.

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

СМ. ТАКЖЕ

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

Если вы захотите больше узнать ометапрограммировании,обращайтесь к статье «Python Metaclasses»1 на сайте Real Python.

1 https://realpython.com/python-metaclasses/.

Книги для программистов: https://t.me/booksforits