- •Об авторе
- •О группе редакторов
- •Предисловие
- •Введение
- •Как использовать эту книгу
- •Загрузка исходного кода CPython
- •Что в исходном коде?
- •Настройка среды разработки
- •IDE или редактор?
- •Настройка Visual Studio
- •Настройка Visual Studio Code
- •Настройка Vim
- •Выводы
- •Компиляция CPython
- •Компиляция CPython на macOS
- •Компиляция CPython на Linux
- •Установка специализированной версии
- •Знакомство с Make
- •Make-цели CPython
- •Компиляция CPython на Windows
- •Профильная оптимизация
- •Выводы
- •Грамматика и язык Python
- •Спецификация языка Python
- •Генератор парсеров
- •Повторное генерирование грамматики
- •Выводы
- •Конфигурация и ввод
- •Конфигурация состояния
- •Структура данных конфигурации среды выполнения
- •Конфигурация сборки
- •Сборка модуля из входных данных
- •Выводы
- •Генерирование конкретного синтаксического дерева
- •Парсер/токенизатор CPython
- •Абстрактные синтаксические деревья
- •Важные термины
- •Пример: добавление оператора «почти равно»
- •Выводы
- •Компилятор
- •Исходные файлы
- •Важные термины
- •Создание экземпляра компилятора
- •Флаги будущей функциональности и флаги компилятора
- •Таблицы символических имен
- •Основная компиляция
- •Ассемблер
- •Создание объекта кода
- •Использование Instaviz для вывода объекта кода
- •Пример: реализация оператора «почти равно»
- •Выводы
- •Цикл вычисления
- •Исходные файлы
- •Важные термины
- •Построение состояния потока
- •Построение объектов кадров
- •Выполнение кадра
- •Стек значений
- •Пример: добавление элемента в список
- •Выводы
- •Управление памятью
- •Выделение памяти в C
- •Проектирование системы управления памятью Python
- •Аллокаторы памяти CPython
- •Область выделения объектной памяти и PyMem
- •Область выделения сырой памяти
- •Нестандартные области выделения памяти
- •Санитайзеры выделенной памяти
- •Арена памяти PyArena
- •Подсчет ссылок
- •Сборка мусора
- •Выводы
- •Параллелизм и конкурентность
- •Модели параллелизма и конкурентности
- •Структура процесса
- •Многопроцессорный параллелизм
- •Многопоточность
- •Асинхронное программирование
- •Генераторы
- •Сопрограммы
- •Асинхронные генераторы
- •Субинтерпретаторы
- •Выводы
- •Объекты и типы
- •Примеры этой главы
- •Встроенные типы
- •Типы объектов
- •Тип type
- •Типы bool и long
- •Тип строки Юникода
- •Словари
- •Выводы
- •Стандартная библиотека
- •Модули Python
- •Модули Python и C
- •Набор тестов
- •Запуск набора тестов в Windows
- •Запуск набора тестов в Linux или macOS
- •Флаги тестирования
- •Запуск конкретных тестов
- •Модули тестирования
- •Вспомогательные средства тестирования
- •Выводы
- •Отладка
- •Обработчик сбоев
- •Компиляция поддержки отладки
- •LLDB для macOS
- •Отладчик Visual Studio
- •Отладчик CLion
- •Выводы
- •Бенчмаркинг, профилирование и трассировка
- •Использование timeit для микробенчмарка
- •Использование набора тестов производительности Python
- •Профилирование кода Python с использованием cProfile
- •Выводы
- •Что дальше?
- •Создание расширений C для CPython
- •Улучшение приложений Python
- •Участие в проекте CPython
- •Дальнейшее обучение
- •Препроцессор C
- •Базовый синтаксис C
- •Выводы
- •Благодарности
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