dataclass语法
一、 简介
官方文档的地址为:https://docs.python.org/3.9/library/dataclasses.html
dataclass的定义位于PEP-557,根据定义一个dataclass是指“一个带有默认值的可变的namedtuple”,广义的定义就是有一个类,它的属性均可公开访问,可以带有默认值并能被修改,而且类中含有与这些属性相关的类方法,那么这个类就可以称为dataclass,再通俗点讲,dataclass就是一个含有数据及操作数据方法的容器。
乍一看可能会觉得这个概念不就是普通的class么,然而还是有几处不同:
- 相比普通class,dataclass通常不包含私有属性,数据可以直接访问
- dataclass的repr方法通常有固定格式,会打印出类型名以及属性名和它的值
- dataclass拥有
__eq__
和__hash__
魔法方法 - dataclass有着模式单一固定的构造方式,或是需要重载运算符,而普通class通常无需这些工作
我们来创建一个实例:
from dataclasses import dataclass
@dataclass
class InventoryItem:
"""Class for keeping track of an item in inventory."""
name: str
unit_price: float
quantity_on_hand: int = 0
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
同时,我们也可以添加__init__
方法:
def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0):
self.name = name
self.unit_price = unit_price
self.quantity_on_hand = quantity_on_hand
同时使用dataclass也有一些好处,它比namedtuple更灵活。同时因为它是一个常规的类,所以你可以享受继承带来的便利。
二、 装饰器参数
参数为dataclass()
:
-
init
:如果为true(默认),__init__()
将生成一个方法。如果类已经定义
__init__()
,则忽略此参数。 -
repr
:如果为true(默认),__repr__()
将生成一个方法。生成的 repr 字符串将具有类名以及每个字段的名称和 repr,按照它们在类中定义的顺序。不包括标记为从 repr 中排除的字段。例如: 。InventoryItem(name='widget', unit_price=3.0, quantity_on_hand=10)
如果类已经定义
__repr__()
,则忽略此参数。 -
eq
:如果为true(默认),__eq__()
将生成一个方法。此方法按顺序比较类,就好像它是其字段的元组一样。比较中的两个实例必须是相同的类型。如果类已经定义
__eq__()
,则忽略此参数。 -
order
: 如果为真(默认为False
),将生成__lt__()
、__le__()
、__gt__()
和方法。__ge__()
这些按顺序比较类,就好像它是其字段的元组一样。比较中的两个实例必须是相同的类型。如果order
为真且eq
为假,ValueError
则引发 a。如果该类已经定义了
__lt__()
、__le__()
、__gt__()
或中的任何一个,__ge__()
则TypeError
引发。 -
unsafe_hash
:ifFalse
(默认),__hash__()
根据howeq
andfrozen
are set生成一个方法。__hash__()
由 built-in 使用hash()
,并且在将对象添加到散列集合(例如字典和集合)时使用。拥有 a__hash__()
意味着类的实例是不可变的。可变性是一个复杂的属性,它取决于程序员的意图、 的存在和行为,以及装饰器中的和标志__eq__()
的值。eq``frozen
dataclass()
默认情况下, 除非这样做是安全的,否则
dataclass()
不会隐式添加方法。__hash__()
它也不会添加或更改现有的明确定义的__hash__()
方法。如文档中所述,设置类属性对 Python 具有特定含义。__hash__ = None
__hash__()
如果
__hash__()
没有显式定义,或者如果设置为None
,则可以添加隐式方法。虽然不推荐,但您可以强制使用 . 如果您的类在逻辑上是不可变的,但仍然可以发生变异,则可能会出现这种情况。这是一个专门的用例,应该仔细考虑。dataclass()
__hash__()
dataclass()
__hash__()
unsafe_hash=True
以下是管理方法隐式创建的规则
__hash__()
。请注意,您不能__hash__()
在数据类和 set 中都有显式方法unsafe_hash=True
;这将导致一个TypeError
.如果
eq
和frozen
都为真,默认情况下dataclass()
会为你生成一个__hash__()
方法。如果eq
为真且frozen
为假,__hash__()
将设置为None
,将其标记为不可散列(它是,因为它是可变的)。如果eq
为假,__hash__()
将保持不变,这意味着__hash__()
将使用超类的方法(如果超类是object
,这意味着它将回退到基于 id 的散列)。 -
frozen
:如果为真(默认为False
),分配给字段将产生异常。这模拟只读冻结实例。如果__setattr__()
或__delattr__()
在类中定义,则TypeError
引发。
@dataclass
class C:
...
@dataclass()
class C:
...
@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)
class C:
...
三、 数据属性
1、 参数
参数为field()
:
-
default
:如果提供,这将是该字段的默认值。这是必需的,因为field()
调用本身会替换默认值的正常位置。 -
default_factory
:如果提供,它必须是一个零参数的可调用对象,当该字段需要默认值时将被调用。除其他目的外,这可用于指定具有可变默认值的字段,如下所述。default
同时指定和是错误的default_factory
。 -
init
:如果为 true(默认值),则此字段作为参数包含在生成的__init__()
方法中。 -
repr
:如果为true(默认),则该字段包含在生成的__repr__()
方法返回的字符串中。 -
compare
: 如果为 true(默认值),则该字段包含在生成的相等和比较方法中(__eq__()
、、__gt__()
等)。 -
h