一文带你了解什么是DataClass?

开发 后端
如果你对dataclass还不了解,那么本篇将是你开启学习的最好的一篇文章,因为你不但可以了解 Python 数据类装饰器而且还会掌握如何有效的使用它。

Python dataclass(数据类)简介

Python 在版本 3.7 (PEP 557) 中引入了dataclass。dataclass允许你用更少的代码和更多的开箱即用功能来定义类。

下面定义了一个具有两个实例属性 name 和 age 的常规 Person 类:

class Person:

def __init__(self, name, age):

self.name = name

self.age = age

这个 Person 类具有初始化 name 和 age 属性的__init__ 方法。

如果你想要一个 Person 对象的字符串表示,你需要实现__str__ 或 __repr__方法。另外,如果要通过属性比较 Person 类的两个实例,则需要实现__eq__方法。

但是,如果你使用数据类,你将拥有所有这些功能(甚至更多),而无需实现这些 dunder 方法。

要使 Person 类成为数据类,请执行以下步骤:

首先,从 dataclasses 模块导入 dataclass 装饰器:

from dataclasses import dataclass

其次,用 dataclass 装饰器装饰 Person 类并声明属性:

@dataclass
class Person:
name: str
age: int

在这个例子中,Person 类有两个属性 name 类型为 str 和 age 类型为 int, 这样@dataclass 装饰器隐式创建__init__方法,如下所示:

def __init__(name: str, age: int)

请注意,类中声明的属性的顺序将决定__init__ 方法中参数的顺序。

你可以创建 Person 的对象:

p1 = Person('John', 25)

当打印出 Person 的对象时,你会得到一个可读的格式:

print(p1)

输出:

Person(name='John', age=25)

此外,如果你比较两个具有相同属性值的 Person 对象,它将返回 True。例如:

p1 = Person('John', 25)
p2 = Person('John', 25)
print(p1 == p2)

输出

True

下面讨论数据类提供的其他功能。

默认值

使用常规类时,你可以定义属性的默认值。例如,以下 Person 类的 iq 参数的默认值为 100。

class Person:
def __init__(self, name, age, iq=100):
self.name = name
self.age = age
self.iq = iq

要为数据类中的属性定义默认值,请将其分配给属性,如下所示:

from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
iq: int = 100
print(Person('John Doe', 25))

与参数规则一样,具有默认值的属性必须出现在没有默认值的属性之后。因此,以下代码将不起作用:

from dataclasses import dataclass
@dataclass
class Person:
iq: int = 100
name: str
age: int

转换为元组或字典

dataclasses 模块具有 astuple() 和 asdict() 函数,它们将数据类的实例转换为元组和字典。例如:

from dataclasses import dataclass, astuple, asdict
@dataclass
class Person:
name: str
age: int
iq: int = 100
p = Person('John Doe', 25)
print(astuple(p))
print(asdict(p))

输出:

('John Doe', 25, 100)
{'name': 'John Doe', 'age': 25, 'iq': 100}

创建不可变对象

要从数据类创建只读对象,可以将数据类装饰器的冻结参数设置为 True。例如:

from dataclasses import dataclass, astuple, asdict
@dataclass(frozen=True)
class Person:
name: str
age: int
iq: int = 100

如果你在创建对象后尝试更改其属性,则会收到错误消息。例如:

p = Person('Jane Doe', 25)
p.iq = 120

错误信息:

dataclasses.FrozenInstanceError: cannot assign to field 'iq'

自定义属性行为

如果不想在 __init__ 方法中初始化属性,可以使用 dataclasses 模块中的 field() 函数。

以下示例定义了使用 __init__方法初始化的 can_vote 属性:

from dataclasses import dataclass, field
class Person:
name: str
age: int
iq: int = 100
can_vote: bool = field(init=False)

field() 函数有多个有趣的参数,例如 repr、hash、compare 和 metadata。

如果要初始化一个依赖于另一个属性值的属性,可以使用__post_init__ 方法。顾名思义,Python 在 __init__方法之后调用 __post_init__ 方法。

下面使用__post_init__ 方法根据 age 属性初始化 can_vote 属性:

from dataclasses import dataclass, field
@dataclass
class Person:
name: str
age: int
iq: int = 100
can_vote: bool = field(init=False)
def __post_init__(self):
print('called __post_init__ method')
self.can_vote = 18 <= self.age <= 70
p = Person('Jane Doe', 25)
print(p)

输出:

called the __post_init__ method
Person(name='Jane Doe', age=25, iq=100, can_vote=True)

对对象进行排序

默认情况下,数据类实现 __eq__方法。

要允许不同类型的比较,如__lt__、__lte__、__gt__、__gte__,你可以将 @dataclass 装饰器的 order 参数设置为 True:

@dataclass(order=True)

通过这样做,数据类将按每个字段对对象进行排序,直到找到不相等的值。

在实践中,你经常希望通过特定属性而不是所有属性来比较对象。为此,你需要定义一个名为 sort_index 的字段并将其值设置为要排序的属性。

例如,假设你有一个 Person 对象列表,并希望按年龄对它们进行排序:

members = [
Person('John', 25),
Person('Bob', 35),
Person('Alice', 30)
]

因为,需要:

  • 首先,将 order=True 参数传递给 @dataclass 装饰器。
  • 其次,定义 sort_index 属性并将其 init 参数设置为 False。
  •  第三,在 __post_init__方法中将 sort_index 设置为 age 属性,以按年龄对 Person 的对象进行排序。

from dataclasses import dataclass, field
@dataclass(order=True)
class Person:
sort_index: int = field(init=False, repr=False)
name: str
age: int
iq: int = 100
can_vote: bool = field(init=False)
def __post_init__(self):
self.can_vote = 18 <= self.age <= 70
# sort by age
self.sort_index = self.age
members = [
Person(name='John', age=25),
Person(name='Bob', age=35),
Person(name='Alice', age=30)
]
sorted_members = sorted(members)
for member in sorted_members:
print(f'{member.name}(age={member.age})')

输出:

John(age=25)
Alice(age=30)
Bob(age=35)

总结

  • 使用 dataclasses 模块中的 @dataclass 装饰器使类成为数据类。数据类对象默认实现__eq__和__str__。
  • 使用 astuple() 和 asdict() 函数将数据类的对象转换为元组和字典。
  • 使用 freeze=True 定义一个对象不可变的类。
  • 使用 __post_init__ 方法初始化依赖于其他属性的属性。
  • 使用 sort_index 指定数据类对象的排序属性。
责任编辑:庞桂玉 来源: python运维技术
相关推荐

2019-07-04 15:16:52

数据挖掘大数据算法

2022-09-06 11:21:49

光网络光纤

2023-05-17 11:33:45

梯度下降机器学习

2022-03-14 08:01:06

LRU算法线程池

2019-04-19 14:03:52

APISDK接口

2023-04-11 08:01:32

Web 开发源代码映射

2018-10-22 08:14:04

2023-11-20 08:18:49

Netty服务器

2022-11-11 19:09:13

架构

2023-11-06 08:16:19

APM系统运维

2019-11-14 09:16:56

物联网技术路由器

2024-05-27 00:00:00

.NET游戏引擎C#

2022-02-24 07:34:10

SSL协议加密

2023-10-27 08:15:45

2023-11-08 08:15:48

服务监控Zipkin

2020-02-02 15:14:24

HTTP黑科技前端

2022-04-28 09:22:46

Vue灰度发布代码

2020-10-08 14:32:57

大数据工具技术

2023-03-31 08:16:53

Flutter优化内存管理

2023-12-06 16:28:56

点赞
收藏

51CTO技术栈公众号