True и False в Python 3 имеют разные размеры

Python 2.7:

>>> False.__sizeof__()
24
>>> True.__sizeof__()
24

Python 3.x:

>>> False.__sizeof__()
24
>>> True.__sizeof__()
28

Почему в Python 3 размер True больше размера False?

Так происходит, поскольку тип bool является подклассом int и в Python 2, и в Python 3.

>>> issubclass(bool, int)
True

Но реализация int изменилась.

В Python 2 int имел размер 32 или 64 бита, в зависимости от системы, а long — произвольную длину.

В Python 3 int произвольной длины: long из Python 2 был переименован в int, а исходный int полностью удален.

В Python 2 можно наблюдать такое же поведение для long-объектов 1L и 0L:

>>> import sys
>>> sys.getsizeof(1L)
28
>>> sys.getsizeof(0L)
24

long (int в Python 3) — объект переменной длины, как и кортеж, — выделяется достаточное количество памяти для хранения всех двоичных цифр, необходимых для его представления. Длина переменной части хранится в заголовке объекта. Нулю не нужны двоичных цифры (его переменная длина равна 0), но в случае с единицей происходит переполнение, и требуются дополнительные цифры.

То есть 0 представляется как двоичная строка нулевой длины:

<>

А единица представляется как 30-битная двоичная строка:

<000000000000000000000000000001>

Python в конфигурации по умолчанию использует 30 бит для uint32_t; поэтому 2**30-1 по-прежнему укладывается в 28 байтов на x86-64, а для 2**30 потребуется уже 32.

2**30-1 будет представляться так:

<111111111111111111111111111111>

Т. е. значения всех 30 битов будут установлены в 1; числу 2**30 потребуется больше, у него будет внутреннее представление:

<000000000000000000000000000001000000000000000000000000000000>

Поскольку True использует 28 байт, а не 24, можно не беспокоиться. True — синглтон и поэтому всего 4 байта в общей сложности уйдет на любую программу Python, а не по 4 на каждый True.


Спасибо Antti Haapala.