← Назад к вопросам

Как работает int с памятью в Python?

2.0 Middle🔥 201 комментариев
#Python Core#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает int с памятью в Python

Это фундаментальный вопрос о том, как Python управляет памятью для целочисленных объектов. Понимание этого поможет написать более эффективный код.

1. Кеширование малых целых чисел

Python кеширует целые числа от -5 до 256 для оптимизации памяти:

# Кеширует
a = 256
b = 256
print(a is b)  # True — один объект в памяти
print(id(a) == id(b))  # True

# Не кеширует
c = 257
d = 257
print(c is d)  # False — разные объекты
print(id(c) == id(d))  # False

# Проверим диапазон кеширования
for i in range(-10, 270):
    x = i
    y = i
    if x is not y:
        print(f"Cache ends at {i-1}")
        break

Почему? Числа -5..256 используются чаще всего в Python программах, поэтому CPython кеширует их для экономии памяти и скорости.

2. Размер объекта int в памяти

Каждый int имеет overhead:

import sys

# Малое число (кешировано)
small_int = 100
print(sys.getsizeof(small_int))  # 28 байт

# Большое число
large_int = 10**18
print(sys.getsizeof(large_int))  # 40+ байт

# Очень большое число
huge_int = 10**1000
print(sys.getsizeof(huge_int))  # 160+ байт

Вывод: чем больше число, тем больше памяти оно занимает. Python использует переменное представление для целых чисел (не фиксированный размер как в C).

3. Внутреннее представление int

Python 3 использует оптимизированное представление для целых чисел:

# Python 3 — неограниченная точность
num = 10**100
print(num)  # Работает без проблем

# Представление в памяти (PyLong структура)
# struct PyLongObject {
#     PyObject_HEAD
#     Py_ssize_t ob_size;  // количество цифр
#     digit *ob_digit;     // массив цифр
# }

# Число хранится как массив 30-битных "цифр"
num = 2**60  # 2 "цифры" (64 бита)
num = 2**61  # 3 "цифры"

4. Кешпроблемы в циклах

Знание о кешировании важно для оптимизации:

import timeit

# Медленно — создание новых объектов для 257+
def slow_func():
    total = 0
    for i in range(1000):
        total += i
    return total

# Быстро — переиспользование кешированных объектов
def fast_func():
    total = 0
    for i in range(-5, 100):
        total += i
    return total

print(timeit.timeit(slow_func, number=10000))
print(timeit.timeit(fast_func, number=10000))

5. Присваивание и идентичность

# Копирование vs присваивание
a = 100
b = a
print(a is b)  # True — указывают на один объект

# Изменение (целые числа неизменяемые)
a = 101
print(a is b)  # False — разные объекты

# Почему?
# Целые числа в Python НЕИЗМЕНЯЕМЫЕ (immutable)
# Когда меняешь переменную, создаётся новый объект

x = 5
old_id = id(x)
x += 1  # Это создаёт новый объект!
print(old_id == id(x))  # False

6. Утечки памяти и циклические ссылки

# Циклическая ссылка НЕ утекает для int (они неизменяемые)
class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

# Циклическая ссылка
node1 = Node(1)
node2 = Node(2)
node1.next = node2
node2.next = node1  # Циклическая ссылка

# Python GC соберёт эту память благодаря cycle detection
del node1, node2  # Память освобождена

# Проверка утечек памяти
import gc

# Посмотри, сколько объектов в памяти
print(f"Objects: {len(gc.get_objects())}")
print(f"Referrers of int 100: {len(gc.get_referrers(100))}")

7. Оптимизация использования памяти

# Неоптимально — создание промежуточных объектов
for i in range(1000000):
    x = i
    y = i + 1
    z = i + 2
    # Каждую итерацию создаются новые объекты

# Оптимально — переиспользование переменных
x = y = z = 0
for i in range(1000000):
    x = i
    y = i + 1
    z = i + 2
    # Меньше переходов в создание новых объектов

# Лучше использовать для больших вычислений
import numpy as np
arr = np.arange(1000000, dtype=np.int64)
# NumPy эффективнее работает с большими коллекциями чисел

8. Сравнение == vs is

# == проверяет значение
a = 257
b = 257
print(a == b)  # True
print(a is b)  # False — разные объекты!

# is проверяет идентичность (id)
# Используй is только при необходимости проверки идентичности

# Правильно
if x is None:  # is для None
    pass

# Для чисел используй ==
if x == 100:
    pass

9. Профилирование памяти

import tracemalloc

# Начни отслеживание памяти
tracemalloc.start()

# Твой код
numbers = [i for i in range(100000)]

# Получи статистику
current, peak = tracemalloc.get_traced_memory()
print(f"Current: {current / 1024:.1f} KB")
print(f"Peak: {peak / 1024:.1f} KB")
tracemalloc.stop()

10. Практические выводы

  • Кешированы числа -5..256 — переиспользуются в памяти
  • Большие числа занимают больше памяти — используй numpy для больших массивов
  • Целые числа неизменяемые — операции создают новые объекты
  • Python GC очищает циклические ссылки — не беспокойся о утечках для int
  • Используй == для сравнения значений — is только для None и специальных случаев
  • Профилируй при необходимости — tracemalloc и memory_profiler помогут

Помни: оптимизация памяти для целых чисел обычно не критична, если ты не работаешь с миллионами объектов. Фокусируйся на алгоритмической сложности в первую очередь!

Как работает int с памятью в Python? | PrepBro