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. 一个开源、跨平台的.NET UI框架 - Avalonia UI

    前言 今天大姚给大家分享一个开源.免费(MIT License).跨平台的.NET UI框架:Avalonia UI. Avalonia是一个成熟稳定的平台,用于构建桌面.嵌入式.移动的和Web应用程 ...

  2. Angular Material 18+ 高级教程 – Material Form Field

    介绍 Form Field 或 Text Field 是 Material Design 独有的设计风格 .它长这样 注:Material Design 管它叫 Text Field,Angular ...

  3. 大模型应用开发初探 : 通用函数调用Planner

    大家好,我是Edison. 上一篇,我们了解了什么是AI Agent以及如何用Semantic Kernel手搓一个AI Agent.有朋友留言说,自动函数调用对大模型有较高的要求,比如Azure O ...

  4. Spring —— IoC入门案例

    IoC入门案例   思路分析:     1.管理什么?(Service与Dao)     2.如何将被管理的对象告知IoC容器?(配置)     3.被管理的对象交给IoC容器,如何获取到IoC容器? ...

  5. Flutter Engage 活动精彩回顾 | 中文字幕视频

    在 Flutter Engage 预告之后,无数开发者充满期待并且在社区中积极讨论交流,分享见解.今天,我们正式发布 Flutter 2.0,并在 Flutter Engage 活动 中详细介绍了这一 ...

  6. 剪枝的应用,bfs判重 蚱蜢跳——蓝桥p642

    **问题描述 总共有九个盘子,八只蚱蜢,且每个盘子中只能容下一只蚱蜢,蚱蜢的编号为1~8,如果蚱蜢所在的盘子紧邻着空盘子,那么该蚱蜢可以从自己的盘子跳到空盘子中,也可以隔一个盘子跳到空盘子中,问一开始 ...

  7. Android复习(三)清单文件中的元素——>grant-uri-permission、instrumentation、intent-filter、manifest、meta-data

    <grant-uri-permission> 语法: <grant-uri-permission android:path="string" android:pa ...

  8. AI五子棋_07 落子点四周棋形获取

    AI五子棋 第七步 恭喜你到达第七步! 到这一步,你对战场环境就有了充分的了解.下面我们准备打造机器大脑了.你可能已经有你自己的想法了,不过别着急,先跟着我的思路做.我会提示你解决一些基本的问题. 棋 ...

  9. Nuxt.js 应用中的 server:devHandler 事件钩子详解

    title: Nuxt.js 应用中的 server:devHandler 事件钩子详解 date: 2024/10/26 updated: 2024/10/26 author: cmdragon e ...

  10. AI赋能-《用ChatGPT做软件测试》新书上市

    图书链接京东: https://item.jd.com/10121763192532.html当当: http://product.dangdang.com/29797547.html内容简介本书以目 ...