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之DataClass的更多相关文章

  1. Python中dataclass库

    目录 dataclass语法 一. 简介 二. 装饰器参数 三. 数据属性 1. 参数 2. 使用示例 3. 注意事项 四. 其他 1. 常用函数 2. 继承 3. 总结 dataclass语法 一. ...

  2. Python 3.7 将引入 dataclass 装饰器

    简评:Python 3.7 将于今年夏天发布,Python 3.7 中将会有许多新东西,最激动人心的新功能之一是 dataclass 装饰器. 什么是 Data Class 大多数 Python 开发 ...

  3. Python 3.X简史——记录3.0之后的重要更新

    Python 3.0在2008年12月3日正式发布,在之后又经历了多个小版本(3.1,3.2,3.3……),本文梳理Python 3.0之后的新特性. 其实每个版本都有大量更新,都写出来要几百页,这里 ...

  4. Python3.7 dataclass使用指南

    本文将带你走进python3.7的新特性dataclass,通过本文你将学会dataclass的使用并避免踏入某些陷阱. dataclass简介 dataclass的使用 定义一个dataclass ...

  5. Python3.7 dataclass 介绍

    Posted on 2018年6月28日 by laixintao 1 Comment Python3.7 加入了一个新的 module:dataclasses.可以简单的理解成“支持默认值.可以修改 ...

  6. Python 装饰器入门(下)

    继续上次的进度:https://www.cnblogs.com/flashBoxer/p/9847521.html 正文: 装饰类 在类中有两种不通的方式使用装饰器,第一个和我们之前做过的函数非常相似 ...

  7. Python爬虫学习 - day1 - 爬取图片

    利用Python完成简单的图片爬取 最近学习到了爬虫,瞬时觉得很高大上,想取什么就取什么,感觉要上天.这里分享一个简单的爬取汽车之家文章列表的图片教程,供大家学习. 需要的知识点储备 本次爬虫脚本依赖 ...

  8. python 类的使用

    目录 类的继承 类的派生 类的组合 菱形继承问题 多态与多态性 dataclass的使用 类的继承 什么是继承,在生活中,子承父业,父亲和儿子就是继承的关系 在python中,父类和子类(派生类),父 ...

  9. 整理了8个Python中既冷门又实用的技巧

    1.print 打印带有颜色的信息 大家知道 Python 中的信息打印函数 print,一般我们会使用它打印一些东西,作为一个简单调试. 但是你知道么,这个 Print 打印出来的字体颜色是可以设置 ...

  10. python数据类

    前言 之前有写过一篇python元类的笔记,元类主要作用就是在要创建的类中使用参数metaclass=YourMetaclass调用自定义的元类,这样就可以为所有调用了这个元类的类添加相同的属性了. ...

随机推荐

  1. 【YashanDB知识库】存储过程报错snapshot too old

    问题描述 20231127上午客户反馈绩效系统20231125.20231126出现2次YAS-02020 snapshot too old的问题,测试也有类似问题. 该过程是客户新增的存储过程,目的 ...

  2. (零) React Native 项目开发拾遗

    一位离职的前端同事,最近接了个 React Native 的活儿,遇到许多搞不定的问题,于是找到我帮忙"补课"(没有系统的学习 React Native,也不具备原生 Androi ...

  3. CSS 实现滑动整个元素

    其实没什么难点,主要就是两个CSS属性 scroll-snap-type 这个是作用在包裹容器身上的. scroll-snap-align 这个是作用在被包裹容器身上的. 效果如下图所示: 代码如下: ...

  4. hexo使用小技巧

    1.在博客中加入图片 使用语法 {% asset_img 1.jpg %} 这样hexo会自动渲染1.jpg.,然后1.jpg的位置需要放在同文件名的文件夹中,比如这篇博客叫hexo使用小技巧,那么这 ...

  5. ASP.NET Core C# 反射 & 表达式树 (第四篇)

    前言 上一篇说完了动态创建表达式树, 这篇来说一说解析表达式树. 我之所以会用到是因为最近开始大量使用 trigger 来维护冗余. 但 trigger 本身并不好维护 (EF Core 也不支持), ...

  6. Session——基本使用

    Session    Session 原理 Session 使用细节      

  7. 智和信通搭建高可靠、真稳定IT运维平台,助力能源行业高效生产

    在能源企业信息化高度发展的背景下,北京智和信通有限公司推出全栈式运维管控平台--"智和网管平台",助力能源企业搭建高可靠.真稳定的IT运维平台,实现高效稳定生产. 信息化飞速发展, ...

  8. USB gadget configfs

    概述 USB Linux Gadget是一种具有UDC (USB设备控制器)的设备,可以连接到USB主机,以扩展其附加功能,如串口或大容量存储能力. 一个gadget被它的主机视为一组配置,每个配置都 ...

  9. yaml.load与yaml.dump的用法

    import yaml #向yaml文件中写 with open("E:\个人\ rename.yaml", 'w') as f: project = {'在远方':"1 ...

  10. Excel读写之xlrd模块

    1.1.xlrd模块介绍 xlrd:用于读取Excle数据文件将返回的数据对象放到内存中,然后查询数据文件对象的相关信息. xlwt:用于在内存中生成新的数据文件对象,处理完成后写入到Excel数据文 ...