Канон / лаборатория 1

Что лежит в байтах

Настоящее содержимое памяти восьми объектов, снятое ctypes.string_at(id(obj), sizeof) и разложенное по полям.

CPython 3.11.15Linux x86-64байты реальные, не нарисованные

Механизм, описанный словами, и механизм, который покрутил руками, оседают по-разному. Ниже — не иллюстрация, а дамп: каждый байт снят из живого процесса, каждое поле проверено на совпадение с известным значением (счётчик, длина, хеш, указатель на тип). Наведите курсор на поле в таблице — соответствующие байты подсветятся.

1Как это повторить

Всё, что здесь показано, снимается пятью строками. Вставляется в терминал или ноутбук как есть:

import ctypes, sys, struct

obj = 2**70
n = sys.getsizeof(obj)
raw = ctypes.string_at(id(obj), n)
print(n, raw.hex(' '))
print("refcnt:", struct.unpack_from("<q", raw, 0)[0])
print("type is int:", struct.unpack_from("<Q", raw, 8)[0] == id(int))
print("ob_size:", struct.unpack_from("<q", raw, 16)[0])
print("digits:", [struct.unpack_from("<I", raw, 24 + 4*i)[0] for i in range(3)])

Аккуратно: string_at читает сырую память по адресу. Ошибка в длине — сегфолт всего процесса, а не исключение. Это ровно та граница, за которой Python перестаёт быть безопасным языком.

2Что из этого стоит унести

Числа получены на CPython 3.11.15, Linux x86-64. На другой версии часть из них будет другой — и это не оговорка, а содержание: раскладка объекта 🔧 деталь реализации целиком. Поле wstr у строк, которое здесь занимает восемь байт, в 3.12 просто удалили.