所谓的不可变的类就是类的实例不可修改。
下面我们先看一下普通的类:
In [1]: class A(object):
...: pass
...:
In [2]: a = A()
In [3]: a.abc = 1
In [4]: a.abc
Out[4]: 1
普通的类的实例可以在运行时添加新的属性。
那么如何定义一个不可变的类呢? 下面就来看一个不可变类的例子:
In [8]: class B(object):
....: __slots__ = ['abc']
....: def __init__(self, abc):
....: super(B, self).__setattr__('abc', abc)
....: def __setattr__(self, name, value):
....: raise AttributeError("'%s' has no attribute %s" % (self.__class__, name))
....:
In [9]: b = B(123)
In [10]: b.abc
Out[10]: 123
In [11]: b.abc = 4
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-15-fecd1642a038> in <module>()
----> 1 b.abc = 4
<ipython-input-12-030c2c96393c> in __setattr__(self, name, value)
4 super(B, self).__setattr__('abc', abc)
5 def __setattr__(self, name, value):
----> 6 raise AttributeError("'%s' has no attribute %s" % (self.__class__, name))
7
AttributeError: '<class '__main__.B'>' has no attribute abc
In [12]: b.__dict__
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-18-25106575ab93> in <module>()
----> 1 b.__dict__
AttributeError: 'B' object has no attribute '__dict__'
In [13]: b.x = 1
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-20-0205c051c209> in <module>()
----> 1 b.x = 1
<ipython-input-12-030c2c96393c> in __setattr__(self, name, value)
4 super(B, self).__setattr__('abc', abc)
5 def __setattr__(self, name, value):
----> 6 raise AttributeError("'%s' has no attribute %s" % (self.__class__, name))
7
AttributeError: '<class '__main__.B'>' has no attribute x
这里有两个要点:一个是 __slots__ 另一个是 __setattr__ 。
通过定义 __slots__ 替换掉了类的实例的 __dict__ 属性,阻止新增属性。 通过覆盖 __setattr__ 方法,阻止修改现有属性的值。
Comments