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

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

PyObject_GenericGetDict() реализует логику получения экземпляра словаря для заданного объекта. PyObject_GetAttr()выполняет реализацию __getattr__ () по умолчанию, а PyObject_SetAttr() реализует __setattr__().

ТИПЫ BOOL И LONG

Тип bool — самая прямолинейная реализация встроенных типов. Он наследуется от long и содержит предопределенные константы Py_True и Py_False. Эти константы являются неизменяемыми экземплярами, создаваемыми при инстанцировании интерпретатора Python.

Внутри Objects boolobject.c находится вспомогательная функция для создания экземпляра bool из числа:

Objects boolobject.c, строка 28

PyObject *PyBool_FromLong(long ok)

{

PyObject *result;

if (ok)

result = Py_True;

else

result = Py_False; Py_INCREF(result); return result;

}

Эта функция использует C для вычисления числового типа, чтобы присвоить result значение Py_True или Py_False и увеличить счетчик ссылок.

Числовые функции для and, xor и or реализованы, но операции сложения, вычитания и деления заблокированы из базового типа long, так как деление двух логических значений не имеет смысла.

Реализация and для значения bool построена так, что сначала проверяет, являются ли a и b логическими типами. Если условие не выполняется, значения преобразуются в числа и операция выполняется с двумя числами:

Objects boolobject.c, строка 61

static PyObject * bool_and(PyObject *a, PyObject *b)

{

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

Типы bool и long    269

if (!PyBool_Check(a) || !PyBool_Check(b))

return PyLong_Type.tp_as_number->nb_and(a, b); return PyBool_FromLong((a == Py_True) & (b == Py_True));

}

Тип long

Тип long немного сложнее bool. При переходе от Python 2 к Python 3 CPython перестал поддерживать тип int, и основным целочисленным типом стал long.

Тип long в Python отличается тем, что он способен хранить значение вариативной (изменяемой) длины. Максимальная длина задается в скомпилированном двоичном файле.

Структура данных long в Python состоит из заголовка переменной PyObject и списка цифр. Список цифр ob_digit изначально состоит из одной цифры, но при инициализации расширяется:

Include longintrepr.h, строка 85

struct _longobject {

PyObject_VAR_HEAD digit ob_digit[1];

};

Например, числу 1 будет соответствовать ob_digit [1], а числу 24 601 — ob_digit [2, 4, 6, 0, 1].

Память для нового значения long выделяется вызовом _PyLong_New(). Эта функция получает фиксированную длину и проверяет, что она меньше MAX_ LONG_DIGITS. Затем память для ob_digit выделяется заново в соответствии с длиной.

Чтобы преобразовать тип long языка C в тип long языка Python, C long преобразуется в список цифр, выделяется память для Python long, после чего задается значение каждой цифры.

Для чисел из одной цифры объект long инициализируется с ob_digit, уже имеющим длину 1. Затем значение задается без выделения памяти:

Objects longobject.c, строка 297

PyObject * PyLong_FromLong(long ival)

{

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

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

PyLongObject *v; unsigned long abs_ival;

unsigned long t; /* unsigned, поэтому >> не распространяет бит знака */ int ndigits = 0;

int sign;

CHECK_SMALL_INT(ival);

...

/* Быстрая ветвь для целых чисел из одной цифры */ if (!(abs_ival >> PyLong_SHIFT)) {

v = _PyLong_New(1); if (v) {

Py_SIZE(v) = sign;

v->ob_digit[0] = Py_SAFE_DOWNCAST( abs_ival, unsigned long, digit);

}

return (PyObject*)v;

}

...

/* Большие числа: цикл для определения количества цифр */ t = abs_ival;

while (t) { ++ndigits;

t >>= PyLong_SHIFT;

}

v = _PyLong_New(ndigits); if (v != NULL) {

digit *p = v->ob_digit;

Py_SIZE(v) = ndigits*sign; t = abs_ival;

while (t) {

*p++ = Py_SAFE_DOWNCAST(

t & PyLong_MASK, unsigned long, digit); t >>= PyLong_SHIFT;

}

}

return (PyObject *)v;

}

Преобразование числа с плавающей точкой double в Python long осуществляется вызовом PyLong_FromDouble().

Другие функции реализации в Objects longobject.c содержат вспомогательные функции, например функцию PyLong_FromUnicodeObject() для преобразования строки Юникода в число.

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

Типы bool и long    271

Пример

Слот типа расширенного сравнения для long заполняется long_richcompare(). Эта функция является оберткой для long_compare():

Objects longobject.c, строка 3031

static PyObject *

long_richcompare(PyObject *self, PyObject *other, int op)

{

Py_ssize_t result;

CHECK_BINOP(self, other); if (self == other)

result = 0;

else

result = long_compare((PyLongObject*)self, (PyLongObject*)other);

Py_RETURN_RICHCOMPARE(result, 0, op);

}

Функция long_compare() сначала проверяет длину (количество цифр) двух переменных: a и b. Если длины совпадают, то она перебирает в цикле все цифры и проверяет, равны ли они друг другу.

long_compare() возвращает один из трех видов значений:

1.Если a < b, возвращается отрицательное число.

2.Если a == b, возвращается 0.

3.Если a > b, возвращается положительное число.

Например, при выполнении условия 1 == 5 результат будет равен -4. Для 5 == 1 результат равен 4.

Можно добавить следующий блок кода перед макросом Py_RETURN_RICHCOMPARE, чтобы он возвращал True, если абсолютное значение результата <=1. Макрос Py_ABS()возвращает абсолютное целое значение со знаком:

if (op == Py_AlE) {

if (Py_ABS(result) <= 1) Py_RETURN_TRUE;

else

Py_RETURN_FALSE;

}

Py_RETURN_RICHCOMPARE(result, 0, op);

}

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