Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Определение неизменяемых объектов в Python
Это важная концепция для понимания производительности, безопасности и предсказуемости кода. За 10+ лет я выработал методы быстро определять, может ли объект изменяться или нет.
Встроенные типы: изменяемые vs неизменяемые
# НЕИЗМЕНЯЕМЫЕ (Immutable)
int_obj = 42 # int
float_obj = 3.14 # float
str_obj = "hello" # str
bool_obj = True # bool
none_obj = None # NoneType
complex_obj = 3 + 4j # complex
frozenset_obj = frozenset([1, 2, 3]) # frozenset
bytes_obj = b"data" # bytes
range_obj = range(10) # range
tuple_obj = (1, 2, 3) # tuple (если содержит immutable)
# ИЗМЕНЯЕМЫЕ (Mutable)
list_obj = [1, 2, 3] # list
dict_obj = {"a": 1} # dict
set_obj = {1, 2, 3} # set
bytearray_obj = bytearray(b"data") # bytearray
Способ 1: Проверка через хеш (hash)
Неизменяемые объекты можно хешировать:
# Неизменяемый объект — можно хешировать
try:
hash_value = hash((1, 2, 3)) # tuple
print(f"Хеш tuple: {hash_value}") # Работает
except TypeError:
print("Объект неизменяемый")
# Попытка хешировать список (изменяемый)
try:
hash_value = hash([1, 2, 3]) # list
print(f"Хеш list: {hash_value}")
except TypeError as e:
print(f"Список не hashable: {e}")
# TypeError: unhashable type: 'list'
Способ 2: Попытка изменить объект
# Попытаемся изменить tuple
tuple_obj = (1, 2, 3)
try:
tuple_obj[0] = 99 # Попытаемся изменить
except TypeError as e:
print(f"Tuple неизменяемый: {e}")
# TypeError: 'tuple' object does not support item assignment
# Список можно изменить
list_obj = [1, 2, 3]
list_obj[0] = 99 # Работает!
print(list_obj) # [99, 2, 3]
Способ 3: Проверка через id() при переприсваивании
# Неизменяемый объект — переприсваивание создаёт новый объект
str1 = "hello"
id_before = id(str1)
str2 = str1 + " world" # Новый объект
id_after = id(str2)
print(id_before == id_after) # False — разные объекты
# Изменяемый объект — изменение оставляет же объект
list1 = [1, 2, 3]
id_before = id(list1)
list1.append(4) # Изменяем существующий объект
id_after = id(list1)
print(id_before == id_after) # True — ТОТ ЖЕ объект
Способ 4: Использование inspect модуля
import inspect
from collections.abc import Hashable
def is_immutable(obj) -> bool:
"""Проверяет, неизменяемый ли объект"""
# Способ 1: проверяем, можно ли хешировать
try:
hash(obj)
return True
except TypeError:
return False
def is_mutable(obj) -> bool:
"""Проверяет, изменяемый ли объект"""
return not is_immutable(obj)
# Тестирование
print(is_immutable(42)) # True
print(is_immutable("hello")) # True
print(is_immutable((1, 2, 3))) # True
print(is_immutable([1, 2, 3])) # False
print(is_immutable({1, 2, 3})) # False
print(is_immutable(frozenset([1, 2]))) # True
Способ 5: Проверка через типы
from typing import get_origin, get_args
# Встроенные неизменяемые типы
IMMUTABLE_TYPES = (
int, float, str, bool, bytes, type(None),
complex, frozenset, tuple, range
)
# Встроенные изменяемые типы
MUTABLE_TYPES = (
list, dict, set, bytearray
)
def quick_check_immutable(obj) -> bool:
"""Быстрая проверка по типу"""
return type(obj) in IMMUTABLE_TYPES
def quick_check_mutable(obj) -> bool:
"""Быстрая проверка по типу"""
return type(obj) in MUTABLE_TYPES
print(quick_check_immutable("hello")) # True
print(quick_check_mutable([1, 2, 3])) # True
Способ 6: Кастомные неизменяемые классы
from dataclasses import dataclass
# Способ 1: использовать @dataclass с frozen=True
@dataclass(frozen=True)
class ImmutablePoint:
"""Неизменяемая точка"""
x: float
y: float
point = ImmutablePoint(1.0, 2.0)
print(hash(point)) # Работает! Можно использовать как ключ
# Попытка изменить
try:
point.x = 3.0
except AttributeError as e:
print(f"Нельзя изменить: {e}")
# AttributeError: can't set attribute
# Способ 2: использовать __slots__ и __setattr__
class ImmutableUser:
"""Неизменяемый пользователь"""
__slots__ = ("name", "email")
def __init__(self, name: str, email: str):
object.__setattr__(self, "name", name)
object.__setattr__(self, "email", email)
def __setattr__(self, name, value):
raise AttributeError("Object is immutable")
def __hash__(self):
return hash((self.name, self.email))
def __eq__(self, other):
if not isinstance(other, ImmutableUser):
return False
return self.name == other.name and self.email == other.email
user = ImmutableUser("John", "john@example.com")
print(hash(user)) # Работает!
# Попытка изменить
try:
user.name = "Jane"
except AttributeError as e:
print(f"Нельзя изменить: {e}")
Сложный случай: tuple с изменяемыми элементами
# Tuple сам по себе неизменяемый, но может содержать изменяемые объекты
mixed_tuple = (1, 2, [3, 4]) # tuple содержит list
# Нельзя изменить сам tuple
try:
mixed_tuple[0] = 99 # TypeError
except TypeError:
print("Нельзя изменить элементы tuple")
# Но можно изменить список ВНУТРИ tuple
mixed_tuple[2].append(5) # Работает!
print(mixed_tuple) # (1, 2, [3, 4, 5]) — список изменился!
# Попытка хешировать
try:
hash(mixed_tuple) # TypeError!
except TypeError:
print("Tuple с изменяемыми элементами не hashable")
# Вывод: даже если контейнер неизменяемый, если он содержит
# изменяемые объекты, то он не hashable!
Практические примеры: когда это важно
# Использование как ключ в dict — только неизменяемые!
data = {}
# OK — tuple неизменяемый
data[(1, 2, 3)] = "point"
print(data) # {(1, 2, 3): 'point'}
# Ошибка — список изменяемый
try:
data[[1, 2, 3]] = "point"
except TypeError as e:
print(f"Ошибка: {e}")
# TypeError: unhashable type: 'list'
# Использование в set — только неизменяемые!
unique_items = set()
unique_items.add(("x", "y")) # OK
print(unique_items) # {('x', 'y')}
try:
unique_items.add(["x", "y"]) # Ошибка
except TypeError:
print("Списки нельзя добавлять в set")
Быстрый чеклист
# Вопрос: объект неизменяемый?
# Ответ: можно ли его хешировать?
def check_immutable_quick(obj) -> bool:
try:
hash(obj)
return True # Неизменяемый
except TypeError:
return False # Изменяемый
# Вывод: если hash() работает — объект неизменяемый!
Почему это важно?
- Производительность: неизменяемые объекты можно оптимизировать
- Безопасность: неизменяемые объекты safe для многопоточности
- Функциональное программирование: гарантирует отсутствие побочных эффектов
- Кэширование: неизменяемые объекты можно кэшировать
- Ключи в dict/set: только неизменяемые объекты
Просто запомни: если object hashable (можно вызвать hash()), то он неизменяемый. Это универсальный способ проверить в любой ситуации.