Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Иммутабельные (неизменяемые) объекты в Python
Иммутабельность — свойство объекта, при котором его состояние не может быть изменено после создания. Это критично для написания безопасного и предсказуемого кода.
Встроенные иммутабельные типы
1. int (целое число)
# int иммутабелен
x = 5
print(id(x)) # 140734667394528
# Попытка "изменить" создаёт новый объект
x = x + 1
print(id(x)) # 140734667394560 (другой объект!)
# Python оптимизирует малые числа (-5 до 256)
x = 5
y = 5
print(id(x) == id(y)) # True (один объект)
z = 257
w = 257
print(id(z) == id(w)) # False (разные объекты)
2. str (строка)
# Строка иммутабельна
text = "hello"
print(id(text)) # 140734667394528
# Попытка "изменить" создаёт новую строку
text = text + " world"
print(id(text)) # 140734667394560 (новая строка)
# Строковые методы возвращают новую строку
original = "Hello World"
lowercased = original.lower() # Не меняет original
print(original) # "Hello World" (без изменений)
print(lowercased) # "hello world" (новая строка)
3. tuple (кортеж)
# Кортеж иммутабелен
t = (1, 2, 3)
print(id(t)) # 140734667394528
# Нельзя изменить элемент
t[0] = 99 # TypeError: 'tuple' object does not support item assignment
# Нельзя добавить элемент
t.append(4) # AttributeError: 'tuple' object has no attribute 'append'
# Но элементы могут быть мутабельными!
t = ([1, 2], 3) # Кортеж содержит список
t[0].append(4) # OK! Список иммутабелен, но его содержимое можно менять
print(t) # ([1, 2, 4], 3)
4. frozenset (неизменяемое множество)
# frozenset иммутабелен
fs = frozenset([1, 2, 3])
print(id(fs)) # 140734667394528
# Нельзя добавить или удалить
fs.add(4) # AttributeError: 'frozenset' object has no attribute 'add'
# Можно использовать как ключ в словаре (в отличие от set)
my_dict = {fs: "value"} # OK
# Но обычный set нельзя
my_set = {1, 2, 3}
my_dict = {my_set: "value"} # TypeError: unhashable type: 'set'
5. bytes (байты)
# bytes иммутабелен
b = b"hello"
print(id(b)) # 140734667394528
# Нельзя изменить
b[0] = 99 # TypeError: 'bytes' object does not support item assignment
# Но bytearray мутабелен
ba = bytearray(b"hello")
ba[0] = ord('H')
print(ba) # bytearray(b'Hello')
6. bool, None, float
# Все иммутабельны
true_val = True
false_val = False
none_val = None
float_val = 3.14
# Изменение создаёт новый объект
true_val = False # Новое назначение, не изменение
Мутабельные типы (для сравнения)
1. list (список)
# Список мутабелен
my_list = [1, 2, 3]
print(id(my_list)) # 140734667394528
# Изменение НЕ создаёт новый объект
my_list[0] = 99
print(id(my_list)) # 140734667394528 (тот же объект!)
print(my_list) # [99, 2, 3]
# Добавление элемента
my_list.append(4)
print(id(my_list)) # 140734667394528 (всё ещё тот же объект)
print(my_list) # [99, 2, 3, 4]
2. dict (словарь)
# Словарь мутабелен
my_dict = {"a": 1, "b": 2}
print(id(my_dict)) # 140734667394528
# Изменение
my_dict["a"] = 99
print(id(my_dict)) # 140734667394528 (тот же объект)
print(my_dict) # {"a": 99, "b": 2}
# Добавление
my_dict["c"] = 3
print(id(my_dict)) # 140734667394528
print(my_dict) # {"a": 99, "b": 2, "c": 3}
3. set (множество)
# Множество мутабельно
my_set = {1, 2, 3}
print(id(my_set)) # 140734667394528
my_set.add(4)
print(id(my_set)) # 140734667394528 (тот же объект)
print(my_set) # {1, 2, 3, 4}
Создание собственных иммутабельных объектов
1. Использование @dataclass с frozen=True
from dataclasses import dataclass
@dataclass(frozen=True)
class Point:
x: int
y: int
point = Point(1, 2)
print(id(point)) # 140734667394528
# Попытка изменить
point.x = 5 # FrozenInstanceError: cannot assign to field 'x'
# Можно использовать как ключ
my_dict = {point: "location"}
my_set = {point, Point(3, 4)}
2. Использование slots и свойств
class ImmutablePoint:
__slots__ = ('_x', '_y')
def __init__(self, x, y):
object.__setattr__(self, '_x', x)
object.__setattr__(self, '_y', y)
@property
def x(self):
return self._x
@property
def y(self):
return self._y
def __setattr__(self, name, value):
raise AttributeError("can't set attribute")
def __hash__(self):
return hash((self._x, self._y))
def __eq__(self, other):
return isinstance(other, ImmutablePoint) and \
self._x == other._x and self._y == other._y
point = ImmutablePoint(1, 2)
print(point.x) # 1
point.x = 5 # AttributeError: can't set attribute
# Можно использовать как ключ
my_dict = {point: "location"}
3. Использование namedtuple
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
point = Point(1, 2)
print(point.x) # 1
point.x = 5 # AttributeError: can't set attribute
# Хеширует автоматически
my_dict = {point: "location"}
my_set = {point, Point(3, 4)}
Преимущества иммутабельности
1. Безопасность в многопоточной программе
import threading
# Иммутабельный объект безопасен без блокировок
immutable_tuple = (1, 2, 3)
def thread1():
for i in range(1000000):
_ = immutable_tuple # Безопасно
def thread2():
for i in range(1000000):
_ = immutable_tuple # Безопасно
t1 = threading.Thread(target=thread1)
t2 = threading.Thread(target=thread2)
t1.start()
t2.start()
t1.join()
t2.join()
# Никакой race condition!
# Мутабельный список требует синхронизации
from threading import Lock
mutable_list = [1, 2, 3]
lock = Lock()
def safe_append(item):
with lock:
mutable_list.append(item) # Требует блокировки
2. Использование как ключ в словаре
# Иммутабельные объекты можно использовать как ключи
coordinates = {
(0, 0): "origin",
(1, 1): "point_a",
(2, 2): "point_b"
}
# Мутабельные — нельзя
my_dict = {
[0, 0]: "origin" # TypeError: unhashable type: 'list'
}
3. Понятность и предсказуемость кода
def process_data(data: tuple):
# Знаем, что data не изменится внутри функции
for item in data:
print(item)
# data всё ещё то же самое
# vs
def process_data(data: list):
# data может быть изменён
for item in data:
print(item)
# data может быть другим!
# (если функция его изменила)
4. Кеширование результатов
from functools import lru_cache
# Кеш работает только с иммутабельными аргументами
@lru_cache(maxsize=128)
def expensive_function(data: tuple):
return sum(data)
result = expensive_function((1, 2, 3)) # OK, кешируется
# С мутабельными — не работает
@lru_cache(maxsize=128)
def process_list(data: list):
return sum(data)
result = process_list([1, 2, 3]) # TypeError: unhashable type: 'list'
Таблица иммутабельности
| Тип | Иммутабелен | Хеширует | Юзкейс |
|---|---|---|---|
| int | Да | Да | Числа, счётчики |
| str | Да | Да | Текст, идентификаторы |
| tuple | Да | Да | Неизменяемые наборы данных |
| frozenset | Да | Да | Уникальные значения, ключи |
| bytes | Да | Да | Двоичные данные |
| bool | Да | Да | Логические значения |
| None | Да | Да | Отсутствие значения |
| list | Нет | Нет | Динамические коллекции |
| dict | Нет | Нет | Ключ-значение хранилище |
| set | Нет | Нет | Уникальные элементы |
| bytearray | Нет | Нет | Изменяемые байты |
Выводы
- Иммутабельные объекты (int, str, tuple, frozenset, bytes) не меняются после создания
- Мутабельные объекты (list, dict, set) можно изменять
- Преимущества иммутабельности: потокобезопасность, использование как ключи, кеширование
- Используй tuple вместо list, когда данные не меняются
- Используй frozenset вместо set, когда нужны ключи словаря
- Создавай собственные иммутабельные классы с @dataclass(frozen=True)
Иммутабельность — основа чистого и безопасного кода!