简单使用
dataclasses 可以用来快速的定义数据类,并能够简单明了的指明该类所具有的属性和类型,比如,要定义一个名为 Person
的类,常规的写法如下:
class Person:
def __int__(self, id: int, first_name: str, last_name: str, eye_color: str):
self.id = id
self.first_name = first_name
self.last_name = last_name
self.eye_color = eye_color
如果使用 dataclasses ,写法则会简单很多:
from dataclasses import dataclass
@dataclass
class Person:
id: int
first_name: str
last_name: str
eye_color: str
dataclasses 将属性都作为类属性定义,不需要再写一遍参数,再写一遍实例属性绑定了,不仅写起来方便,看起来也很清晰。而且在初始化实例时,也会有对应参数的类型提示。
看起来如此简单,那么 dataclasses 还做了哪些其他的工作呢?
数据展示
试着初始化一个实例并看看样子:
>>> john = Person(1, first_name="John", last_name="Doe", eye_color="black")
>>> print(john)
Person(id=1, first_name='John', last_name='Doe', eye_color='black')
可以通过 print
输出的命令同样也很清晰的代表了实例的内容。看来 dataclasses 同时也为 Person
定义了 __str__
和 __repr__
方法。
数据对比
如果再初始化一个实例,并与之前的对比呢?属性不同的话,期望的结果也是不相等的,试试看:
>>> bob = Person(2, first_name="Bob", last_name="Doe", eye_color="black")
>>> print(john == bob)
False
那么如果属性一致,那么期望结果也是相等的:
>>> john2 = Person(1, first_name="John", last_name="Doe", eye_color="black")
>>> print(john2 == john)
True
属性冻结
如果希望生成的实例属性不可变更,可以加入 frozen=True
参数:
@dataclass(frozen=True)
class Person:
id: int
first_name: str
last_name: str
eye_color: str
此时对实例做属性更改,则会遇到异常:
>>> john = Person(1, first_name="John", last_name="Doe", eye_color="black")
>>> john.last_name = 'Jan'
Traceback (most recent call last):
File "...", line 20, in <module>
john.last_name = 'Jan'
File "<string>", line 4, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'last_name'
定义初始化参数
如果有的参数,只想让它在初始化时传入,但是不要作为实例属性,可以通过 __post_init__
方法处理,比如,现在想在 Person
的实例化时接收一个 city_id
作为所在城市的数据信息 id
,但是在真正调用的时候,希望能够通过 person.city
直接读取到 city_id
所代表的内容。可以这样处理:
from dataclasses import dataclass, InitVar, field
class City(object):
@classmethod
def from_id(cls, id):
return cls()
@dataclass
class Person:
id: int
first_name: str
last_name: str
eye_color: str
city_id: InitVar[int]
city: City = field(init=False)
def __post_init__(self, city_id: int):
self.city = City.from_id(city_id)
其他参数
除上述之外, dataclass
装饰器还支持很多定制化的参数,比如 kw_only
是否支持只传入关键字,order
是否支持大于、小于等比较操作,具体可参考官方文档。