Как сделать класс неизменным в python?
Я много читал об этом предмете, но я все еще не могу найти подходящий ответ.
У меня есть класс вроде:
class A(object):
def __init__(self, first, second):
self.first = first
self.second = second
def __eq__(self, other):
return ****
def __str__(self):
return *****
def __repr__(self):
return ****
a = A("a", "b")
Как я могу запретить a.first = "c", например?
Ответы
Ответ 1
Вы можете переопределить __setattr__
, чтобы предотвратить любые изменения:
def __setattr__(self, name, value):
raise AttributeError('''Can't set attribute "{0}"'''.format(name))
или запретить добавлять новые атрибуты:
def __setattr__(self, name, value):
if not hasattr(self, name):
raise AttributeError('''Can't set attribute "{0}"'''.format(name))
# Or whatever the base class is, if not object.
# You can use super(), if appropriate.
object.__setattr__(self, name, value)
Вы также можете заменить hasattr
на проверку на список разрешенных атрибутов:
if name not in list_of_allowed_attributes_to_change:
raise AttributeError('''Can't set attribute "{0}"'''.format(name))
Другой подход заключается в использовании свойств вместо простых атрибутов:
class A(object):
def __init__(self, first, second):
self._first = first
self._second = second
@property
def first(self):
return self._first
@property
def second(self):
return self._second
Ответ 2
Вы можете отключить __setattr__
как последний шаг инициализации объекта.
class A(object):
def __init__(self, first, second):
self.first = first
self.second = second
self.frozen = True
def __setattr__(self, name, value):
if getattr(self, 'frozen', False):
raise AttributeError('Attempt to modify immutable object')
super(A, self).__setattr__(name, value)
>>> a = A(1, 2)
>>> a.first, a.second
(1, 2)
>>> a.first = 3
Traceback (most recent call last):
File "<pyshell#46>", line 1, in <module>
a.first = 3
File "<pyshell#41>", line 10, in __setattr__
raise AttributeError('Attempt to modify immutable object')
AttributeError: Attempt to modify immutable object
Изменить: В этом ответе есть недостаток, который, я уверен, разделяется всеми другими решениями: если сами члены изменяются, ничто не защищает их. Если ваш объект содержит список, например, все это. Это противоречит, например, С++, где объявление объекта const
рекурсивно распространяется на все его элементы.