数据类

自3.7版本开始,Python引入了一个新的功能:数据类(dataclass)。根据PEP-557的定义,数据类是一个带有默认值的可变命名元组。可以认为数据类就是一个类,其中的属性都是公有的,属性都带有默认值并且可以修改,这个类中还可以包含与这些属性相关的方法。

声明一个数据类需要引入dataclasses模块中的dataclass修饰器。以下给出一个简单的数据类示例。

from dataclasses import dataclass, field


@dataclass
def Book:
	name = ""
	isbn = ""
	price = 0.0
	authors = field(default_factory=list)

数据类在定义后会自动产生一个为所有属性赋值的构造函数,并且会自动建立__repr__()__eq__()两个方法。数据类中的属性可以不带有默认值,但是需要注意的是不带默认值的属性要写在带有默认值的属性前面,这与函数参数的书写顺序要求是一致的。

修饰器dataclass可以接受一些参数来自定义数据类的建立,主要的参数有以下这些,全都都只接受布尔类型值。

  • init,指示是否生成构造函数,如果需要自己定义构造函数则应设置为False
  • repr,指示是否生成__repr__()方法。
  • eq,指示是否生成__eq__()方法。
  • order,指示是否生成__lt__()__gt__()__le__()__ge__()等用于比较的方法。
  • unsafe_hash,根据eqfrozen的值来决定是否生成__hash__
  • frozen,设置为True的时候实例对象将是不可变的。

数据类通过dataclass修饰器自动生成的构造函数默认会调用名为__post_init__()的方法,如果使用了默认生成的构造函数,那么一些追加的构造操作可以在__post_init__()方法中书写。

数据类支持继承,dataclass修饰器会检查数据类的所有基类,会将其中出现的其他数据类按顺序添加进当前的数据类中,如果子类的属性与基类的属性重名,则子类的属性会覆盖掉基类的同名属性。

数据类中的每个属性都会在dataclass修饰器的作用下自动转化为dataclasses.Field对象。通常这个自动转换的过程是无需干预的,但是有的时候则需要定制这个转换过程。我们可以通过dataclasses.field()函数来定义一个属性,并声明它的特性。

正如前面示例中的authors属性,这是一个列表,如果直接使用list()或者[]来定义,则会在数据类实例创建的时候仅复制列表的引用,这会造成不必要的混乱。所以使用field()函数来定义这个属性的具体特性。dataclasses.field()函数可以接受以下参数来定制dataclasses.Field对象。

  • default,设置属性的默认值。
  • default_factory,控制如何产生默认值,接受一个callable类型值。
  • repr,是否包含到默认的__repr__()方法输出中。
  • hash,是否参与到生成__hash__中。
  • init,是否参与到构造函数中。
  • compare,是否参与实例比较方法。
  • metadata,使用字典类型值设定属性的元数据,用于第三方扩展使用。

除此之外,dataclasses中还提供了一些常用的工具函数,其功能如下。

  • asdict(),将数据类实例转换为一个字典类型实例。
  • astuple(),将数据类实例转换为一个元组。