2024彻底搞懂Python的Dataclass(1)
本文较长,会分为几期,目标是给大家讲解
Python的dataclass该怎么用,以及它是如何工作的,而不只是和大家一起创建一个dataclass
本文基于Python的版本是3.11,不同的版本的python,dataclass可能会有不同的差异,这是因为dataclass是一个正在不断演进的python特性,变化较大。
Dataclass是什么?
一句话,dataclass是一个代码生成器code generator, 一个用来生成python class的代码生成器。如果你用过Python的collection模块namedtuple,就会比较容易理解代码生成器的概念。
class Student: def __init__(self, name, age):
self.name = name
self.age = age
s1 = Student('Jack', 30)
s2 = Student('Tim', 20)
print(s1.name)
print(s2.age)
# namedtuple可以简化一个class的创建
from collections import namedtuple
Student = namedtuple('Student',['name', 'age'])
s3 = Student('Paul', 55)
s4 = Student('Nico', 40)
print(s3.name)
print(s4.age)
Dataclass基础
如名字dataclasses所示,dataclasses 是用于数据结构的类(在某些方面类似于namedtuple,但dataclasses 提供了更多的可能,因为它们归根结底还是常规的 Python 类,而不是元组)
让我们看看如何使用 dataclasses 生成标准的 Python 类,看看它可以帮我们简化多少工作量。
作为一个例子,我们先创建一个标准的position类,这个类有两个实例属性,x和y,都是float类型。
class Position:
def __init__(self, x: float = 0, y: float = 0,):
self.x = x
self.y = y
创建一个实例
>>> p = Position()
>>> p
<__main__.Position object at 0x10459ae40>
>>> print(p)
<__main__.Position object at 0x10459ae40>
>>>
那为了让它打印出来的内容更好看一些,我们一般可以给这个Class添加__str__和__repr__方法
class Position:
def __init__(self, x: float = 0, y: float = 0,):
self.x = x
self.y = y
def __str__(self):
return f"{self.__class__.__qualname__}(x={self.x}, y={self.y})"
def __repr__(self):
return f"{self.__class__.__qualname__}(x={self.x}, y={self.y})"
>>> p = Position()
>>> p
Position(x=0, y=0)
>>> print(p)
Position(x=0, y=0)
拿上面这个Python类,如果用dataclass实现,就会简单很多,我们看一下。
from dataclasses import dataclass@dataclass
class Position:
x: float = 0
y: float = 0
>>> p = Position()
>>> p
Position(x=0, y=0)
>>> print(p)
Position(x=0, y=0)
就这么简单几行代码,实现了前面的一个传统的Python类。
那为什么说dataclass是一个代码生成器
code generator呢?因为它实际上是通过一个装饰器@dataclass对我们原始定义的类进行了一个修改,然后返回了这个修改后的同一个类,有点拗口,我们证明一下
首先,我们定一个没有装饰器的传统python类
class Position:
x: float = 0
y: float = 0
通过id可以查看这个类在内存中的位置
>>> id(Position)
409177792
然后我们把这个Position类作为参数传递给dataclass, 返回一个新类 NewPosition ,然后查看它内存的位置
>>> NewPosition = dataclass(Position)
>>> id(NewPosition)
409177792
在内存中的位置完全一样,这说明dataclass装饰器并没有创建一个新类,而是在原先类的基础上进行修改。