dataclasses — 数据类
这个模块提供了一个装饰器和一些函数,用于自动添加生成的 special method,例如 init() 和 repr() 到用户定义的类
自动生成内置方法方法
@dataclass
class Person:
...
@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False,
match_args=True, kw_only=False, slots=False)
当你直接使用@dataclass装饰器时,它会默认创建__init__、repr、__eq__内置方法
- init:如果为真值(默认),将生成一个 init() 方法。
如果类已定义 init() ,则忽略此参数。 - repr:如果为真值(默认),将生成一个 repr() 方法。 生成的 repr 字符串将具有类名以及每个字段的名称和 repr ,按照它们在类中定义的顺序。不包括标记为从 repr 中排除的字段
如果类已定义 repr() ,则忽略此参数。 - eq:如果为true(默认值),将生成 eq() 方法。此方法将类作为其字段的元组按顺序比较。比较中的两个实例必须是相同的类型。
如果类已定义 eq() ,则忽略此参数
init示例
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
sex: str = "男"
print(Person(name="小鹏", age=18))
# output:Person(name='小鹏', age=18, sex='男')
在这个例子中,类变量都将包含在__init__()方法中,它们将被定义为
def __init__(self, name: str, age: int, sex: str = "男"):
repr示例
生成的 repr 字符串将具有类名以及每个字段的名称和 repr
#定义一个普通的python类
class Company:
a:str
def __init__(self,a):
self.a = a
#调用repr()函数将对象转化为供解释器读取的形式
print(Person(name="小鹏", age=18))
# output:Person(name='小鹏', age=18, sex='男')
print(Company(a = 1))
# output:<__main__.Company object at 0x000002C2276D3B20
ep示例
此方法将类作为其字段的元组按顺序比较
print(Person(name="小鹏", age=18)==Person(name="小鹏", age=18))
# output:True
print(Company("1")==Company("1"))
# output:False
Field
dataclasses.field(*, default=MISSING, default_factory=MISSING, init=True, repr=True, hash=None, compare=True, metadata=None, kw_only=MISSING)
对于常见和简单的用例,不需要其他功能。但是,有些数据类功能需要额外的每字段信息。为了满足这种对附加信息的需求,你可以通过调用提供的 field() 函数来替换默认字段值
- default:如果提供,这将是该字段的默认值。这是必需的,因为 field() 调用本身会替换一般的默认值。
- default_factory:如果提供,它必须是一个零参数可调用对象,当该字段需要一个默认值时,它将被调用。除了其他目的之外,这可以用于指定具有可变默认值的字段,如下所述。 同时指定 default 和 default_factory 将产生错误。
- init:如果为true(默认值),则该字段作为参数包含在生成的 init() 方法中。
- repr :如果为true(默认值),则该字段包含在生成的 repr() 方法返回的字符串中。
field 示例
使用field为数据类变量提供默认值
@dataclass()
class Company:
name:str
persons: list = field(default_factory=list)
address: str = field(default="北京")
print(Company("测吧"))
# output:Company(name='测吧', persons=[], address='北京')
对象、dict、json互相转换
在数据类中不同类型的转换会有很多的使用场景,接下来展示不同类型的转换示例
对象转换成dict
@dataclass()
class Person:
name: str
age: int
@dataclass()
class Company:
name:str
persons: list[Person] = field(default_factory=list)
address: str = field(default="北京")
p1 = Person("小明",18)
p2 = Person("小红",20)
company = Company("测吧",persons=[p1,p2])
print(asdict(company))
# output:{'name': '测吧', 'persons': [{'name': '小明', 'age': 18}, {'name': '小红', 'age': 20}], 'address': '北京'}
dict转换成对象
dict_data = {'name': '测吧', 'persons': [{'name': '小明', 'age': 18}, {'name': '小红', 'age': 20}], 'address': '北京'}
c1 = Company(**dict_data)
print(c1)
# output:Company(name='测吧', persons=[{'name': '小明', 'age': 18}, {'name': '小红', 'age': 20}], address='北京')
print(type(c1.persons[0]))
# output:<class 'dict'>
这里可以看到,当dict转为对象时,company的person对象信息已经丢失了,persons列表里面的类型已经成了dict
针对dict转换为嵌套对象的场景,dataclass官方没有做这方面的优化,但是我们可以通过第三方库加强dataclass解决这个问题
命令行安装
pip install dataclass-dict-convert
# 添加dataclass_dict_convert注解
@dataclass_dict_convert()
@dataclass()
class Person:
......
@dataclass_dict_convert()
@dataclass()
class Company:
......
dict_data = {'name': '测吧', 'persons': [{'name': '小明', 'age': 18}, {'name': '小红', 'age': 20}], 'address': '北京'}
#通过from_dict方法去实例化对象
c1 = Company.from_dict(dict_data)
print(c1)
# output:Company(name='测吧', persons=[Person(name='小明', age=18), Person(name='小红', age=20)], address='北京')
print(type(c1.persons[0]))
# output:<class '__main__.Person'>
通过使用from_dict方法去实现dict转换成对象,这里可以看到,persons列表里面的元素已经成功转换成person了
json转换对象
#json_data.json
"""
{
"name": "测吧",
"persons": [
{
"name": "小明",
"age": 18
},
{
"name": "小红",
"age": 20
}
],
"address": "北京"
}
"""
with open("./json_data.json",'r',encoding='utf-8') as f:
print(Company.from_json(f.read()))
# output: Company(name='测吧', persons=[Person(name='小明', age=18), Person(name='小红', age=20)], address='北京')
如果对dataclass有更高定制化的需求,建议详细阅读官方文档
https://docs.python.org/zh-cn/3.10/library/dataclasses.html?highlight=dataclass#module-contents