python hook dacite库实现类型强制转换

2024-05-31 15:19:48 浏览数 (2)

前言

之前接到过这样一个需求,从后台某个接口获取配置,配置数据按json格式返回,类似这样:

代码语言:json复制
{
    "data":{
        "id":1,
        "min":30,
        "max":100
    }
}

从配置里面取数据很简单嘛,把json转成dict,直接data["字段名"]就可以取数据,为了规范化,方便以后随时能知道接口有哪些字段,我使用了dataclass来定义,并用dacite库加载数据类

定义dataclass

代码语言:python代码运行次数:0复制
from dataclasses import dataclass

import dacite


@dataclass
class Config:
    id: int
    min: int
    max: int


data = {
    "id": 1,
    "min": 30,
    "max": 100
}

data = dacite.from_dict(data_class=Config, data=data)
print(data.id, data.min, data.max)

遇到问题

以上代码是ok的,但是哪知道同事给我返回数据时,json里面没有返回int类型,全是字符串类型,而且字符串还带浮点,类似这样:

代码语言:json复制
{
    "data" = {
        "id": "1.00",
        "min": "30.00",
        "max": "100.00"
    }
}

这时加载的代码就出错了,会报WrongTypeError,因为定义的是int类型,而字段实际数据是str类型。我只能把dataclass的定义全改成str类型,定义如下:

代码语言:python代码运行次数:0复制
@dataclass
class Config:
    id: str
    min: str
    max: str

可这样也太麻烦了吧,我每次用这个字段,还是要当成int型来用,所以只能这样转:

代码语言:python代码运行次数:0复制
min = "30.00"
min = int(float(min))

一个配置里面有几十个字段,每个字段用到的地方都很多,代码里全是类型转换,心累。

解决问题

看了一下dacite库的源码,直接当标注类型和数据类型不一致时,强制转换类型,这样就可以把数据标注成自己想要的类型,且自动实现强制转换了,代码如下:

代码语言:python代码运行次数:0复制
from typing import Type, Any

import dacite
from dacite import Config
from dacite.core import _build_value


def __build_type(type_: Type, data: Any, config: Config):
    new_data = _build_value(type_=type_, data=data, config=config)
    # 当标注类型和实际数据类型不一致时,进行类型转换
    if not isinstance(new_data, type_):
        # 如果标注类型是int,实际数据是str,且数据是浮点数,转换为整数
        if type_.__name__ == "int" and isinstance(new_data, str):
            new_data = int(float(new_data))
        new_data = type_(new_data)
    return new_data


dacite.core._build_value = __build_type

总结

成功通过替换dacite的函数,实现了类型强制转换的效果,舒服了n_n

改第三方库或者内置库有风险,改之前请务必知道自己的行为会产生什么后果!

0 人点赞