Ответ
Неизменяемый (immutable) объект — это объект, состояние которого нельзя изменить после его создания. Это повышает предсказуемость и безопасность кода, особенно в многопоточных приложениях, а также позволяет использовать объекты в качестве ключей словаря.
В Python есть несколько способов создать неизменяемый класс:
1. @dataclass(frozen=True) (Python 3.7+)
Это самый современный и предпочтительный способ. Декоратор dataclass с параметром frozen=True автоматически делает класс неизменяемым.
from dataclasses import dataclass, FrozenInstanceError
@dataclass(frozen=True)
class Point:
x: int
y: int
p = Point(10, 20)
print(p.x) # 10
try:
p.x = 30 # Попытка изменить атрибут
except FrozenInstanceError as e:
print(e) # Вывод: cannot assign to field 'x'
2. collections.namedtuple
Это фабричная функция для создания простых классов-кортежей. Объекты namedtuple легковесны и неизменяемы по своей природе.
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x) # 10
# Попытка изменения вызовет AttributeError
# p.x = 30 -> AttributeError: can't set attribute
3. Ручная реализация через __slots__ и __setattr__
Этот способ дает полный контроль, но является наиболее многословным. Он полезен для понимания механики неизменяемости.
class ImmutablePoint:
__slots__ = ('x', 'y') # Экономит память и предотвращает создание __dict__
def __init__(self, x, y):
# Используем object.__setattr__ для инициализации полей
super().__setattr__('x', x)
super().__setattr__('y', y)
def __setattr__(self, name, value):
# Переопределяем метод, чтобы запретить изменения
raise AttributeError(f"Can't modify attribute {name}") Ответ 18+ 🔞
Да ты послушай, что за дичь творится с этими объектами! Вот сидишь ты, пишешь код, а он тебе в какой-то момент — раз! — и меняется под носом, как последняя шлюха. А кто поменял? А хуй его знает! Потоков дохуя, все друг другу мозги ебут. Надо это прекращать.
Вот, например, неизменяемый объект — это святое. Создал и спи спокойно, как младенец. Никто его тронуть не посмеет. Никаких сюрпризов. И в словарь его можно сунуть как ключ, и он не сломается, не станет другим, как хитрая жопа твоя бывшая.
В Python, слава богу, есть несколько способов эту святость обеспечить. Смотри сюда, не зевай.
1. @dataclass(frozen=True) (Python 3.7+)
Это, блядь, самый модный и правильный способ сейчас. Надел на класс этот декоратор, сказал frozen=True — и всё, пиздец. Автоматом всё замораживается, как твои яйца в феврале.
from dataclasses import dataclass, FrozenInstanceError
@dataclass(frozen=True)
class Point:
x: int
y: int
p = Point(10, 20)
print(p.x) # 10, всё чётко
try:
p.x = 30 # Пробуем наебать систему
except FrozenInstanceError as e:
print(e) # И получаем по ебалу: cannot assign to field 'x'
Вот и весь сказ. Попробуй изменить — получи FrozenInstanceError прямо в ебальник.
2. collections.namedtuple
Старая, добрая, консервативная штука. Лёгкая, как пух, и неизменяемая от рождения, как пидарас шерстяной. Фабрика по производству кортежей с именами.
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x) # 10, красота
# А теперь попробуй тронь, сука
# p.x = 30 -> AttributeError: can't set attribute
# Вот тебе и вся недолга.
Просто, быстро, без наворотов. Для простых случаев — то, что доктор прописал.
3. Ручная возня с __slots__ и __setattr__
А это, дружок, для истинных мазохистов и ценителей старой школы. Полный контроль, но и писать надо, овердохуища. Зато поймёшь, как эта магия изнутри работает.
class ImmutablePoint:
__slots__ = ('x', 'y') # Экономит память, да и __dict__ не создаёт, чтоб не маялся
def __init__(self, x, y):
# Тут надо хитрить, как лиса. Используем родной __setattr__ от object.
super().__setattr__('x', x)
super().__setattr__('y', y)
def __setattr__(self, name, value):
# А это — священный щит. Любая попытка изменения — получай ошибку в рыло.
raise AttributeError(f"Can't modify attribute {name}, иди нахуй")
Вот так вот, Колян. Создал объект, проинициализировал поля через super().__setattr__, а потом любой вызов обычного __setattr__ посылаешь на три весёлые буквы. Красота, да и только.
Выбирай любой способ, главное — чтобы объекты твои были крепки, как советская дружба, и неизменны, как моё решение больше не звонить этой стерве.