dataclass是python3.7的新特性,是一个主要包含数据的类。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from dataclasses import dataclass, make_dataclass

@dataclass
class DataClassCard:
  rank: str
  suit: str


DataClassCard2 = make_dataclass('DataClassCard2', ['rank', 'suit'])

>>> queen_of_hearts = DataClassCard('Q', 'Hearts')
>>> queen_of_hearts.rank
'Q'
>>> queen_of_hearts
DataClassCard(rank='Q', suit='Hearts')
>>> queen_of_hearts == DataClassCard('Q', 'Hearts')
True

如果我们使用一般方法来创建一个类,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class RegularCard:
  def __init__(self, rank, suit):
    self.rank = rank
    self.suit = suit

>>> queen_of_hearts = RegularCard('Q', 'Hearts')
>>> queen_of_hearts.rank
'Q'
>>> queen_of_hearts
<__main__.RegularCard object at 0x7fb6eee35d30>
>>> queen_of_hearts == RegularCard('Q', 'Hearts')
False

python使用dataclass创建的类,内部已经重写了__init__, __repr__, __eq__等方法。

如果我们要实现这些功能

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class RegularCard
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __repr__(self):
        return (f'{self.__class__.__name__}'
                f'(rank={self.rank!r}, suit={self.suit!r})')

    def __eq__(self, other):
        if other.__class__ is not self.__class__:
            return NotImplemented
        return (self.rank, self.suit) == (other.rank, other.suit)

dataclass可以看做是对namedtuple的替代

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from collections import namedtuple

NamedTupleCard = namedtuple('NamedTupleCard', ['rank', 'suit'])

>>> queen_of_hearts = NamedTupleCard('Q', 'Hearts')
>>> queen_of_hearts.rank
'Q'
>>> queen_of_hearts
NamedTupleCard(rank='Q', suit='Hearts')
>>> queen_of_hearts == NamedTupleCard('Q', 'Hearts')
True

namedtuple有很多限制,因为其本身实质上是tuple,无法修改,无法设置默认值,无法继承等。

设置默认值和类型提示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from dataclasses import dataclass

@dataclass
class CName:
    name: str


@dataclass
class Position:
    name: str
    lon: float = 0.0
    lat: float = 0.0
    names: List[CName]

默认工厂函数(dataclass可变数据类型必须使用)

1
2
3
4
5
6

@dataclass
class D:
    x: list = field(default_factory=list)

assert D().x is not D().x