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. canvas实现图片标记

    前言 由于业务需求,需要有一个图片标记功能,其实就是对图片画框画线做标记,类似微信的图片编辑 但是需要存下标记图及其标记的具体数据,.功能其实很简单,但刚开始的时候也是费了一些功夫的.我将原项目中该功 ...

  2. 丝滑解决Chatgpt频繁奔溃、断网掉线问题

    事件缘由 这段时间使用Chatgpt的时候频繁出现something wrong等断网掉线问题,中间还频繁出现物品转向的人机验证(我那么具有迷惑性吗...),被烦的不行.后面了解到有一个KeepCha ...

  3. SQL无法解决排序规则 Chinese_PRC_CI_AS 和 Latin1_General_CI_AS 的冲突

    最近在执行一些跨库关联查询语句的时候提示了 "Cannot resolve the collatior conflict between "Chinese_PRC_Ci As&qu ...

  4. 给vue+element-ui动态设置主题色(包括外链样式、内联样式、行内样式)

    基本思路 实现思路:实现一个mixins混入的主题js即theme.js,注册到全局下.使用el-color-picker组件切换颜色的时候,把颜色值传递到根root下,在根实例下监听主题色的变化来更 ...

  5. docker 修改容器内容后更新镜像的流程

    在 Docker 中,如果你修改了一个容器的内容并希望将这些更改保存为一个新的镜像,可以按照以下步骤进行: docker version: 26.1 1. 确保容器运行 首先,确保你正在修改的容器是运 ...

  6. Angular – Language Service

    介绍 Angular Language Service 是一个针对 Angular 项目的程序静态分析 (Program Static Analysis) 工具,它的作用是提升开发体验. 很多 IDE ...

  7. innerText 和 inner HTML 的区别

    获取内容时: innerText会自动删除空格和换行:innerHTML会保留空格和换行: <body> <div>获 取内 容</div> <script& ...

  8. 2. react项目【前端】+C#【后端】从0到1

    前端 1. 删除默认的src下所有文件,替换如下文件目录 2. src/index.js:

  9. Vue3 的 nextTick 函数

    作用: DOM 渲染是异步耗时的, vue2.x 需要等到 DOM 渲染完成之后做某个事情,需要使用 this.$nextTick , vue3.x 则直接提供了 nextTick 这个方法去实现 : ...

  10. 阿里云服务器安装mysql镜像

    新创建的服务器首先需要创建安全组,开放端口然后重启服务器 登陆远程服务器,具体操作步骤如下 #拉取镜像 docker pull mysql:5.7 #查看镜像是否拉取到 docker images # ...