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

Что такое id объекта?

1.7 Middle🔥 61 комментариев
#Python Core#Soft Skills

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

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

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

id() — уникальный идентификатор объекта в Python

id() — встроенная функция, которая возвращает уникальный целочисленный идентификатор объекта. Это адрес в памяти, где хранится объект (в CPython). Функция существует для всех объектов в Python.

Базовый синтаксис

obj = "Hello"
identifier = id(obj)
print(identifier)  # Например: 140234567890256 (адрес в памяти)
print(type(identifier))  # <class 'int'>

Что это на самом деле?

В CPython (самая распространённая реализация Python):

# id() возвращает адрес объекта в памяти
import ctypes

obj = "Hello"
obj_id = id(obj)
print(f"Адрес в памяти: {obj_id}")
print(f"В hex: {hex(obj_id)}")

# Получить объект по адресу (опасно!)
addr_obj = ctypes.cast(obj_id, ctypes.py_object).value
print(addr_obj)  # Hello (тот же объект)

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

Это критическая разница:

# == сравнивает ЗНАЧЕНИЯ
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)  # True (одинаковые значения)

# is сравнивает ИДЕНТИЧНОСТЬ (id)
print(a is b)  # False (разные объекты в памяти)
print(id(a))  # 140234567890000
print(id(b))  # 140234567890100 (другой адрес!)

# Но если это один и тот же объект:
c = a
print(a is c)  # True (одинаковый id)
print(id(a) == id(c))  # True

id() и интерны (Interning)

Python оптимизирует некоторые объекты, переиспользуя их в памяти:

Числа: -5 до 256 интернируются

# Маленькие числа интернируются
a = 100
b = 100
print(id(a) == id(b))  # True (один объект в памяти)
print(a is b)  # True

# Большие числа — разные объекты
c = 1000
d = 1000
print(id(c) == id(d))  # False (разные объекты)
print(c is d)  # False

Строки интернируются при определённых условиях

# Строковые литералы интернируются
s1 = "hello"
s2 = "hello"
print(id(s1) == id(s2))  # True (один объект)

# Но если создать через конкатенацию — может быть разный id
s3 = "hel" + "lo"
s4 = "hel" + "lo"
print(id(s3) == id(s4))  # Может быть False (зависит от оптимизаций)

# Явная интернизация
import sys
s5 = sys.intern("hello world")
s6 = sys.intern("hello world")
print(id(s5) == id(s6))  # True (гарантированно)

Использование id() для отладки

class User:
    def __init__(self, name):
        self.name = name
        print(f"Создан User {name}, id={id(self)}")

user1 = User("Alice")  # Создан User Alice, id=140234567890000
user2 = User("Bob")    # Создан User Bob, id=140234567890100

print(f"user1 это user2? {user1 is user2}")  # False

# Отследить копирование объектов
user3 = user1
print(f"user1 это user3? {user1 is user3}")  # True (одна ссылка)
print(id(user1) == id(user3))  # True

id() и типы данных

# Неизменяемые объекты (immutable)
a = 5
print(id(a))  # Фиксированный адрес
# a = 6  — это создаст НОВЫЙ объект, не изменит старый

# Изменяемые объекты (mutable)
my_list = [1, 2, 3]
original_id = id(my_list)
my_list.append(4)  # id() не изменится
print(id(my_list) == original_id)  # True (тот же объект)

# Присваивание создаёт новый объект
my_list = [1, 2, 3, 4]
print(id(my_list) == original_id)  # False (новый объект)

Отличия в разных реализациях Python

# CPython: id это реальный адрес в памяти
import sys
print(sys.implementation.name)  # cpython

# PyPy, Jython, IronPython:
# id может быть просто уникальным числом, не адресом

Практический пример: отслеживание ссылок

class DataCache:
    def __init__(self):
        self.data = {}
    
    def cache_object(self, key, obj):
        # Сохраняем id для отладки
        self.data[key] = {
            "value": obj,
            "id": id(obj),
            "type": type(obj).__name__
        }
    
    def debug_info(self):
        for key, info in self.data.items():
            print(f"{key}: {info['type']} (id={info['id']})")

cache = DataCache()
user = {"name": "Alice", "age": 30}
cache.cache_object("user_1", user)

user["age"] = 31  # Изменяем, но id остаётся
cache.cache_object("user_1", user)
cache.debug_info()
# user_1: dict (id=140234567890000) в обоих случаях

id() и сборка мусора (Garbage Collection)

import gc

def create_objects():
    obj1 = {"data": "temporary"}
    obj2 = [1, 2, 3]
    print(f"obj1 id: {id(obj1)}")
    print(f"obj2 id: {id(obj2)}")
    # Выходим из функции — obj1, obj2 удаляются

create_objects()

# После удаления объекта его id может быть переиспользован
# для нового объекта (переиспользование адреса в памяти)
obj3 = {"data": "new"}  # Может получить тот же id, что был obj1
print(f"obj3 id: {id(obj3)}")

Проверка идентичности в коллекциях

class User:
    def __init__(self, name):
        self.name = name

users = [User("Alice"), User("Bob"), User("Charlie")]
ids_set = {id(user) for user in users}
print(len(ids_set))  # 3 (все разные)

# Проверить, есть ли в списке конкретный объект
alice = users[0]
print(any(user is alice for user in users))  # True

id() для отладки shared состояния

def find_shared_state_issue():
    # Проблема: все элементы указывают на ОДИН объект
    matrix = [[0] * 3 for _ in range(3)]  # ✓ Правильно
    wrong_matrix = [[0] * 3] * 3  # ✗ Неправильно!
    
    print("Правильная матрица:")
    for row in matrix:
        print(id(row), row)
    
    print("\nНеправильная матрица:")
    for row in wrong_matrix:
        print(id(row), row)  # Все id одинаковые!
    
    # Проверка
    wrong_matrix[0][0] = 1
    print(wrong_matrix)  # Все строки изменились!

find_shared_state_issue()

Ключевые моменты

  • id() возвращает адрес объекта в памяти (в CPython)
  • is сравнивает id, == сравнивает значения
  • Интернирование оптимизирует память для часто используемых объектов
  • Неизменяемые объекты часто переиспользуют id
  • Изменяемые объекты (списки, словари) сохраняют id при изменении
  • id() полезен для отладки, но не для production кода