如何在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" 这样的操作呢?
2 个回答
6
你可以在初始化对象的最后一步禁用 __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
编辑:这个回答有个缺陷,我相信其他的解决方案也会有同样的问题:如果对象的成员本身是可变的,那就没有什么能保护它们了。例如,如果你的对象里面有一个列表,那就完蛋了。这和C++不同,在C++中声明一个对象为 const
会递归地扩展到它的所有成员。
5
你可以重写 __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))
另一种方法是使用属性(properties),而不是普通的属性:
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