Python中dataclass库
dataclass语法
一、 简介
官方文档的地址为:https://docs.python.org/3.9/library/dataclasses.html
dataclass的定义位于PEP-557,根据定义一个dataclass是指“一个带有默认值的可变的namedtuple”,广义的定义就是有一个类,它的属性均可公开访问,可以带有默认值并能被修改,而且类中含有与这些属性相关的类方法,那么这个类就可以称为dataclass,再通俗点讲,dataclass就是一个含有数据及操作数据方法的容器。
乍一看可能会觉得这个概念不就是普通的class么,然而还是有几处不同:
- 相比普通class,dataclass通常不包含私有属性,数据可以直接访问
- dataclass的repr方法通常有固定格式,会打印出类型名以及属性名和它的值
- dataclass拥有
__eq__和__hash__魔法方法 - dataclass有着模式单一固定的构造方式,或是需要重载运算符,而普通class通常无需这些工作
我们来创建一个实例:
from dataclasses import dataclass
@dataclass
class InventoryItem:
"""Class for keeping track of an item in inventory."""
name: str
unit_price: float
quantity_on_hand: int = 0
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
同时,我们也可以添加__init__方法:
def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0):
self.name = name
self.unit_price = unit_price
self.quantity_on_hand = quantity_on_hand
同时使用dataclass也有一些好处,它比namedtuple更灵活。同时因为它是一个常规的类,所以你可以享受继承带来的便利。
二、 装饰器参数
参数为dataclass():
init:如果为true(默认),__init__()将生成一个方法。如果类已经定义
__init__(),则忽略此参数。repr:如果为true(默认),__repr__()将生成一个方法。生成的 repr 字符串将具有类名以及每个字段的名称和 repr,按照它们在类中定义的顺序。不包括标记为从 repr 中排除的字段。例如: 。InventoryItem(name='widget', unit_price=3.0, quantity_on_hand=10)如果类已经定义
__repr__(),则忽略此参数。eq:如果为true(默认),__eq__()将生成一个方法。此方法按顺序比较类,就好像它是其字段的元组一样。比较中的两个实例必须是相同的类型。如果类已经定义
__eq__(),则忽略此参数。order: 如果为真(默认为False),将生成__lt__()、__le__()、__gt__()和方法。__ge__()这些按顺序比较类,就好像它是其字段的元组一样。比较中的两个实例必须是相同的类型。如果order为真且eq为假,ValueError则引发 a。如果该类已经定义了
__lt__()、__le__()、__gt__()或中的任何一个,__ge__()则TypeError引发。unsafe_hash:ifFalse(默认),__hash__()根据howeqandfrozenare set生成一个方法。__hash__()由 built-in 使用hash(),并且在将对象添加到散列集合(例如字典和集合)时使用。拥有 a__hash__()意味着类的实例是不可变的。可变性是一个复杂的属性,它取决于程序员的意图、 的存在和行为,以及装饰器中的和标志__eq__()的值。eq``frozendataclass()默认情况下, 除非这样做是安全的,否则
dataclass()不会隐式添加方法。__hash__()它也不会添加或更改现有的明确定义的__hash__()方法。如文档中所述,设置类属性对 Python 具有特定含义。__hash__ = None__hash__()如果
__hash__()没有显式定义,或者如果设置为None,则可以添加隐式方法。虽然不推荐,但您可以强制使用 . 如果您的类在逻辑上是不可变的,但仍然可以发生变异,则可能会出现这种情况。这是一个专门的用例,应该仔细考虑。dataclass()__hash__()dataclass()__hash__()unsafe_hash=True以下是管理方法隐式创建的规则
__hash__()。请注意,您不能__hash__()在数据类和 set 中都有显式方法unsafe_hash=True;这将导致一个TypeError.如果
eq和frozen都为真,默认情况下dataclass()会为你生成一个__hash__()方法。如果eq为真且frozen为假,__hash__()将设置为None,将其标记为不可散列(它是,因为它是可变的)。如果eq为假,__hash__()将保持不变,这意味着__hash__()将使用超类的方法(如果超类是object,这意味着它将回退到基于 id 的散列)。frozen:如果为真(默认为False),分配给字段将产生异常。这模拟只读冻结实例。如果__setattr__()或__delattr__()在类中定义,则TypeError引发。
@dataclass
class C:
...
@dataclass()
class C:
...
@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)
class C:
...
三、 数据属性
1、 参数
参数为field():
default:如果提供,这将是该字段的默认值。这是必需的,因为field()调用本身会替换默认值的正常位置。default_factory:如果提供,它必须是一个零参数的可调用对象,当该字段需要默认值时将被调用。除其他目的外,这可用于指定具有可变默认值的字段,如下所述。default同时指定和是错误的default_factory。init:如果为 true(默认值),则此字段作为参数包含在生成的__init__()方法中。repr:如果为true(默认),则该字段包含在生成的__repr__()方法返回的字符串中。compare: 如果为 true(默认值),则该字段包含在生成的相等和比较方法中(__eq__()、、__gt__()等)。hash: 这可以是 bool 或None. 如果为 true,则此字段包含在生成的__hash__()方法中。如果None(默认),使用compare: 这通常是预期的行为。如果某个字段用于比较,则应在哈希中考虑该字段。None不鼓励将此值设置为除此之外的任何值。hash=False设置的一个可能原因compare=True是,如果一个字段计算哈希值的成本很高,则需要该字段进行相等性测试,并且还有其他字段有助于该类型的哈希值。即使某个字段从哈希中排除,它仍将用于比较。metadata:这可以是映射或无。None 被视为空字典。这个值被包装MappingProxyType()成只读的,并暴露在Field对象上。数据类根本不使用它,而是作为第三方扩展机制提供的。多个第三方可以各自拥有自己的密钥,用作元数据中的命名空间。
2、 使用示例
@dataclass
class C:
x: int
y: int = field(repr=False)
z: int = field(repr=False, default=10)
t: int = 20
3、 注意事项
init参数如果设置为False,表示不为这个field生成初始化操作,dataclass提供了hook——__post_init__供我们利用这一特性:
@dataclass
class C:
a: int
b: int
c: int = field(init=False)
def __post_init__(self):
self.c = self.a + self.b
__post_init__在__init__后被调用,我们可以在这里初始化那些需要前置条件的field。
repr参数表示该field是否被包含进repr的输出,compare和hash参数表示field是否参与比较和计算hash值。metadata不被dataclass自身使用,通常让第三方组件从中获取某些元信息时才使用,所以我们不需要使用这一参数。
如果指定一个field的类型注解为dataclasses.InitVar,那么这个field将只会在初始化过程中(__init__和__post_init__)可以被使用,当初始化完成后访问该field会返回一个dataclasses.Field对象而不是field原本的值,也就是该field不再是一个可访问的数据对象。举个例子,比如一个由数据库对象,它只需要在初始化的过程中被访问:
@dataclass
class C:
i: int
j: int = None
database: InitVar[DatabaseType] = None
def __post_init__(self, database):
if self.j is None and database is not None:
self.j = database.lookup('j')
c = C(10, database=my_database)
四、 其他
1、 常用函数
dataclasses模块中提供了一些常用函数供我们处理数据类。
使用dataclasses.asdict和dataclasses.astuple我们可以把数据类实例中的数据转换成字典或者元组:
>>> from dataclasses import asdict, astuple
>>> asdict(C())
{'name': 'python', 'strong_type': True, 'static_type': False, 'age': 28}
>>> astuple(C())
('python', True, False, 28)
使用dataclasses.is_dataclass可以判断一个类或实例对象是否是数据类
2、 继承
dataclass装饰器会检查当前class的所有基类,如果发现一个dataclass,就会把它的字段按顺序添加进当前的class,随后再处理当前class的field。所有生成的方法也将按照这一过程处理,因此如果子类中的field与基类同名,那么子类将会无条件覆盖基类。子类将会根据所有的field重新生成一个构造函数,并在其中初始化基类。
看个例子:
@dataclass
class Base:
x: float = 25.0
y: int = 0
@dataclass
class C(Base):
z: int = 10
x: int = 15
>>> C()
C(x=15, y=0, z=10)
C中的x则覆盖了Base中的定义
3、 总结
合理使用dataclass将会大大减轻开发中的负担,将我们从大量的重复劳动中解放出来,这既是dataclass的魅力,不过魅力的背后也总是有陷阱相伴,最后我想提几点注意事项:
- dataclass通常情况下是unhashable的,因为默认生成的
__hash__是None,所以不能用来做字典的key,如果有这种需求,那么应该指定你的数据类为frozen dataclass - 小心当你定义了和
dataclass生成的同名方法时会引发的问题 - 当使用可变类型(如list)时,应该考虑使用
field的default_factory - 数据类的属性都是公开的,如果你有属性只需要初始化时使用而不需要在其他时候被访问,请使用
dataclasses.InitVar
只要避开这些陷阱,dataclass一定能成为提高生产力的利器。
Python中dataclass库的更多相关文章
- python中requests库使用方法详解
目录 python中requests库使用方法详解 官方文档 什么是Requests 安装Requests库 基本的GET请求 带参数的GET请求 解析json 添加headers 基本POST请求 ...
- Python中第三方库Requests库的高级用法详解
Python中第三方库Requests库的高级用法详解 虽然Python的标准库中urllib2模块已经包含了平常我们使用的大多数功能,但是它的API使用起来让人实在感觉不好.它已经不适合现在的时代, ...
- Python中cv2库和matplotlib库色彩空间排布不一致
今天在python中读如图片时发现以下问题: 1.在from matplotlib import pyplot as plt之后,再import cv2 cv2.imshow()不能正常使用,还不知道 ...
- Python 中拼音库 PyPinyin 的用法【华为云技术分享】
[摘要] 最近碰到了一个问题,项目中很多文件都是接手过来的中文命名的一些素材,结果在部署的时候文件名全都乱码了,导致项目无法正常运行. 后来请教了一位大佬怎么解决文件名乱码的问题,他说这个需要正面解决 ...
- python中pyperclip库的功能
python3中pyperclip库的功能 作用就是复制.粘贴 例子 import pyperclip pyperclip.copy('Hello world!') pyperclip.paste() ...
- Python中msgpack库的使用
msgpack用起来像json,但是却比json快,并且序列化以后的数据长度更小,言外之意,使用msgpack不仅序列化和反序列化的速度快,数据传输量也比json格式小,msgpack同样支持多种语言 ...
- Python中datetime库的用法
datetime模块用于是date和time模块的合集,datetime有两个常量,MAXYEAR和MINYEAR,分别是9999和1. datetime模块定义了5个类,分别是 1.datetime ...
- Python中的库使用之一 PIL
先上代码:本文主要工给自己参考,在需要的时候直接搜索查找就行了,不想看没有实际运行例子的文档,当参考完这部分还哦未能解决问题在参考PIL的相关文档! Skip to content This repo ...
- Python中第三方库的安装
网上的帖子挺多的,教你如何安装,安装第三方工具库的方法总共分为三类:Dos系统下pip命令:安装包下载安装:IDE集成环境下安装(Pycharm,Spyder……) http://www.jiansh ...
随机推荐
- 非root用户linux下安装FFTW
一.环境准备 确保g++可用本次编译是基于 GNU C++ 环境的,因此务必确定g++编译器可用,使用如下命令验证:命令:g++ --version出现类似如下输出则表明编译器可用: 二.下载FFTW ...
- Calendar类介绍_获取对象的方式和Calendar类的常用成员方式
java.util.Calendar是日历类,在Date后出现,替换掉了许多Date方法.该类将所有可能用到的时间信息封装为静态成员变量,方便获取.日历类就是方便获取各个时间属性的. Calendar ...
- 云存储?不依赖三方服务自己也可以搞,利用Docker来搭建分布式文件系统FastDfs
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_78 对于文件存储来说,一般情况下简单的处理就是在Django配置文件中配置存储目录,按照规则对文件进行上传或者下载. 实际上,当文 ...
- Auto.js pro 开发环境配置
本文仅供学习交流使用,如侵立删!demo下载见文末 Auto.js pro 开发环境配置 准备: 1.Auto.js Pro Auto.js 已暂停维护 -下载链接放在了文章底部,有需要自行下载 2. ...
- 微信小程序检查版本更新并重启
目录 1,前言 2,解决方案 3,调试须知 1,前言 最近开发小程序时候碰上了一个问题,当发布新版本小程序后,需要用户能赶紧用上最新的,避免出问题.查了一下官方文档,总结出几个情况如下: 微信运行时, ...
- Redis安装及常用配置
Redis安装说明 大多数企业都是基于Linux服务器来部署项目,而且Redis官方也没有提供Windows版本的安装包.因此课程中我们会基于Linux系统来安装Redis. 此处选择的Linux版本 ...
- 汇编/C/C++/MFC/JAVA/C# 进阶群103197177
欢迎广大喜欢编程朋友加入进来.如果是大神请分享你的经验,带领广大小伙伴一起打怪升级得经验:如果是编程新人,那么这里是你不二的选择,分享,奉献是我们追求的目标:我们之中大部分是有一年多工作经验的热血编程 ...
- 自动化选课(Python + selenium
前几天听到朋友说自己选课事情,突发奇想想要搞这样一个东西,但是由于各种原因只做到以下的完成度,具体的情况也会在解释的最后留下.这个只适用于曲师大的教务系统,因为用的这个系统来进行的一个调试,对于其 ...
- 如何使能512个virtio_blk设备
一例virtio_blk设备中断占用分析 背景:这个是在客户的centos8.4的环境上复现的,dpu是目前很多 云服务器上的网卡标配了,在云豹的dpu产品测试中,dpu实现的virtio_blk 设 ...
- Qt Q_OBJECT编译问题
编译问题 添加Q_OBJECT后需要qmake 多重继承 添加了Q_ENUM之类的宏,就需要Q_OBJECT 添加了Q_OBJECT,就需要类继承自QObject 如果有多重继承关系,QObject一 ...