Python 3.7 新增了 dataclass
,主要的好处是提供了一个类型定义模板,自动生成常见方法,减少一些常用的重复工作(__init__
、__repr__
、__eq__
、__hash__
和 __lt__
等方法)。
示例
import dataclasses
@dataclasses.dataclass
class User:
user_id: int
user_name: str
first_name: str
last_name: str
age: int = 0
def __post_init__(self):
self.full_name = f'{self.first_name} {self.last_name}'
u = User(1, 'admin', 'Jim', 'Green')
print(u)
# User(user_id=1, user_name='admin', first_name='Jim', last_name='Green', age=0)
print(u.full_name)
# Jim Green
u.full_name = 'Han Meimei'
print(u.full_name)
# Han Meimei
print(dataclasses.asdict(u))
# {'user_id': 1, 'user_name': 'admin', 'first_name': 'Jim', 'last_name': 'Green', 'age': 0}
print(dataclasses.astuple(u))
# (1, 'admin', 'Jim', 'Green', 0)
相当于:
class User:
def __init__(self, user_id: int, user_name: str, first_name: str, last_name: str, age: int = 0):
self.user_id = user_id
self.user_name = user_name
self.first_name = first_name
self.last_name = last_name
self.full_name = f'{self.first_name} {self.last_name}'
self.age = age
def __str__(self):
return f"{self.__class__.__name__}(user_id={self.user_id}, user_name='{self.user_name}', first_name='{self.first_name}', last_name='{self.last_name}, age={self.age}')"
def asdict(self):
return {
'user_id': self.user_id,
'user_name': self.user_name,
'first_name': self.first_name,
'last_name': self.last_name,
'age': self.age,
}
def astuple(self):
return self.user_id, self.user_name, self.first_name, self.last_name, self.age,
u = User(1, 'admin', 'Jim', 'Green')
print(u)
print(u.full_name)
u.full_name = 'Han Meimei'
print(u.full_name)
print(u.asdict())
print(u.astuple())
其他特性
@dataclasses.dataclass(*, init=True, repr=True, eq=True, order=False,
unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False,
weakref_slot=False)
init
是否生成__init__
方法(默认)repr
是否生成__repr__
方法(默认)eq
是否生成__eq__
方法(默认)order
是否生成__lt__
,__le__
,__gt__
,__ge__
方法unsafe_hash
是否生成__hash__
方法
能 hash 的是不会变化对象,否则会出问题,需要谨慎使用。frozen
是否允许对字段赋值
可以使得数据类的实例变成不可变对象,类似于 Python 的namedtuple
。这意味着一旦实例化后,无法修改其中的属性值。match_args
kw_only
是否仅关键词传参slots
是否生成__slots__
方法weakref_slot
是否添加__wrakref__
槽位(弱引用)
指定 weakref_slot=True 而不同时指定 slots=True 将会导致错误。
dataclass
和 __slots__
的区别
dataclass
作为代码模板,作用是简化类的定义
__slots__
的作用是优化内存使用(dataclass 可以通过 slots=True 自动生成 __slots__
定义)
from dataclasses import dataclass
# 使用 dataclass
@dataclass
class Person:
name: str
age: int
email: str = None
# 创建数据类实例
p = Person(name="Alice", age=30)
print(p) # Person(name='Alice', age=30, email=None)
# 使用 __slots__
class PersonWithSlots:
__slots__ = ['name', 'age', 'email']
def __init__(self, name, age, email=None):
self.name = name
self.age = age
self.email = email
# 创建带 __slots__ 的实例
p2 = PersonWithSlots(name="Alice", age=30)
print(p2.name, p2.age) # Alice 30