创建不可变对象

在Python中,自定义不可变对象,其实有点麻烦。

>>> class Number:
...     val: int = 0
...
>>> a = Number()
>>> a.val
0
>>> a.val = 10    #所谓不变对象,就是当用这种方式修改属性值的时候,应该不允许,应该报异常
>>> a.val         #当然,在这里没有报异常,而是实现了修改,因为此处的对象不是不可变的,是可变的。
10

在Python3.7中,有了dataclass,则可以很轻松的实现上述设想。

在下面的代码中,使用了@dataclass装饰器,实现不可变对象。

>>> from dataclasses import dataclass

>>> @dataclass(frozen=True)
... class Book:
...     name: str = "Learn Python with Laoqi"
...
>>> python_book = Book()
>>> python_book.name
'Learn Python with Laoqi'

>>> python_book.name = "other Python Book"    #试图进行修改,结果报异常,不允许修改
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 3, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'name'

用这种方式设置常熟,是不是更优雅。

使用__post_init__进行初始化后处理

什么是初始化后处理?下面举一个例子,说明之:

>>> import math
>>> class Float:
...     def __init__(self, val=0):
...         self.val = val
...         self.process()
...     def process(self):
...         self.decimal, self.integer = math.modf(self.val)
...
>>> a = Float(2.5)
>>> a.decimal
0.5
>>> a.integer
2.0

在类Float中,定义了方法process,并且在初始化方法__init__中调用,这就是要在初始化之后做的事情。

在Python3.7中,具有上述功能代码可以使用__post_init__来完成。如下所示:

>>> @dataclass
... class FloatNumber:
...     val: float = 0.0
...     def __post_init__(self):
...         self.decimal, self.integer = math.modf(self.val)
...
>>> b = FloatNumber(2.5)
>>> b.val
2.5
>>> b.integer
2.0
>>> b.decimal
0.5

是不是再次感受到了“代码的整洁”。