dataclasses --- 数据类

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