Python中dataclass库实例详解
作者:A-L-Kun 发布时间:2023-11-30 02:14:35
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__()
根据howeq
andfrozen
are set生成一个方法。__hash__()
由 built-in 使用hash()
,并且在将对象添加到散列集合(例如字典和集合)时使用。拥有 a__hash__()
意味着类的实例是不可变的。可变性是一个复杂的属性,它取决于程序员的意图、 的存在和行为,以及装饰器中的和标志__eq__()
的值。eq``frozen
dataclass()
默认情况下, 除非这样做是安全的,否则
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一定能成为提高生产力的利器。
来源:https://www.cnblogs.com/liuzhongkun/archive/2022/09/27/16734293.html


猜你喜欢
- 常用的函数和方法在Python中,os库提供了大量与操作系统相关的函数和方法。以下是一些常用的函数和方法及其详细介绍、案例和完整注释:get
- 方法一我常用的做法,就是在数据库中加一个删除标识字段,如: isdel=1 这样就代码删除的字段了方法二直接限制mysql删除启动MySQL
- 关于 json 这个问题,陆陆续续有新手朋友找我问,比如为什么我输出的是 {"1":"item1",
- 一、实例演示1.将一个大Excel等份拆成多个Excel2.将多个小Excel合并成一个大Excel并标记来源work_dir="
- 文章转自微信公众号-Python之禅众所周知,Python 不是一种执行效率较高的语言。此外在任何语言中,循环都是一种非常消耗时间的操作。假
- 使用 sorted() 函数使用 sorted() 函数对字典进行排序,将其转换为元组列表,再按照指定的键或者值进行排序。按照键排序的示例代
- 引子Linux下不支持QQ等功能丰富的IM,虽然可以通过wine运行QQ2012,但是还是喜欢在gtalk群中聊天,gtalk群不支持图片方
- 经过实验,新建一个excel表格,该表格拥有7个sheet,每个sheet有800条数据,其中最后一个sheet为空。首先使用openpyx
- 前言最近在学习微信小程序,在学习的过程中,有很多好玩的 API,经常点外卖的同学可能在小程序中遇到过,比如:某团、某了么都是有显示当前用户位
- <?php /** * Created by JetBrains Ph
- 这段时间看了关于在SQL server 中通过日志和时间点来恢复数据。也看了一些网上的例子,看如何通过日志来恢复数据。 前提条件:数据库的故
- 记一次从web到内网的渗透拓扑图环境介绍现在有三台机器,分别为target1,target2,target3,里面分别有三个flag,每个f
- 目录1. 什么是turtle2. turtle例子3. 其他turtle功能4. 更多的例子5. 总结6. 参考资料1. 什么是turtle
- 简介正则表达式本身是一种小型的、高度专业化的编程语言,而在python中,通过内嵌集成re模块,程序媛们可以直接调用来实现正则匹配。正则表达
- 本文实例讲述了Python中函数参数调用方式。分享给大家供大家参考,具体如下:Python中函数的参数是很灵活的,下面分四种情况进行说明。(
- 本文实例讲述了Python功能键的读取方法。分享给大家供大家参考。具体分析如下:先getch一下得到a,如果等于0或者224,就说明是功能键
- 说起计算机中的时间,还有一些比较有意思的事,比如我们经常听到的Unix时间戳,UTC时间,格林威治时间等,从表示上来讲他们基本属于同一个东西
- 目录一. 加载数据1. 继承Dataset类并重写关键方法2. 使用Dataloader加载数据二. 模型设计三. 训练四. 测试结语pyt
- 在Windows系统下,如何在cmd中输入命令来运行.py文件呢?一. 设置环境变量想要在cmd中运行python文件,必须要设置pytho
- 题目大意问 太阳神有一牛群,由白、黑、花、棕四种颜色的公、母牛组成,其间关系如下,求每种牛的个数。公牛中,白牛多于棕牛,二者之差为