使数据类自动验证其类型
typed-json-dataclass的Python项目详细描述
键入的json数据类
typed_json_dataclass
是一个扩展python3.7的库。
dataclass功能一分为二
主要方式:
- 添加递归获取类字典定义的方法,从而使 数据类JSON可序列化
- 向数据类中添加少量类型验证,以便 验证给定的json是否与 期望。
通过将数据表示为数据类,并使传入的数据 在接收时验证,您可以轻松地在中实现Data Transfer Object (DTO)模式 你的python代码。
这个图书馆可以看作是 attrs, cattrs,和 marshamllow
开始
从pypi安装库:
pip install typed_json_dataclass
像平常一样使用dataclass decorator,但是添加TypedJsonMixin
from
这个库,根据你的类定义。这将向所有数据类添加4个新方法:
- from_dict()
@classmethoddeffrom_dict(cls,raw_dict,*,mapping_mode=MappingMode.NoMap):"""Given a python dict, create an instance of the implementing class. :raw_dict: A dictionary that represents the DTO to create :mapping_mode: Format for properties :returns: Returns an instance of the DTO, instantiated via the dict """
- 来自_json()
@classmethoddeffrom_json(cls,raw_json,*,mapping_mode=MappingMode.NoMap):"""Given a raw json string, create an instance of the implementing class. :raw_json: A json string that represents the DTO to create :mapping_mode: Format for properties :returns: Returns an instance of the DTO, instantiated via the json """
- to_dict()
defto_dict(self,*,keep_none=False,mapping_mode=MappingMode.NoMap,warn_on_initvar=True):"""Express the DTO as a dictionary. :keep_none: Filter keys that are None :mapping_mode: Format for properties :warn_on_initvar: Emit a warning if the instance contains non-default init-only variables. :returns: Returns the instantiated DTO as a dictionary """
- to_json()
defto_json(self,*,keep_none=False,mapping_mode=MappingMode.NoMap,warn_on_initvar=True):"""Express the DTO as a json string. :keep_none: Filter keys that are None :mapping_mode: Format for properties :warn_on_initvar: Emit a warning if the instance contains non-default init-only variables. :returns: Returns the instantiated DTO as a json string """
示例
将数据类转换为json可序列化格式
fromtypingimportListfromdataclassesimportdataclassfromtyped_json_dataclassimportTypedJsonMixin@dataclassclassPerson(TypedJsonMixin):name:strage:int@dataclassclassFamily(TypedJsonMixin):people:List[Person]bob=Person(name='Bob',age=24)alice=Person(name='Alice',age=32)family=Family(people=[bob,alice])print(family.to_json())# => {"people": [{"name": "Bob", "age": 24}, {"name": "Alice", "age": 32}]}
如果您的数据与类型定义不匹配,将出现一个有用的错误:
fromdataclassesimportdataclassfromtyped_json_dataclassimportTypedJsonMixin@dataclassclassPerson(TypedJsonMixin):name:strage:intrequest_data='{"name":"Bob","age":"24"}'bob=Person.from_json(request_data)# => TypeError: Person.age is expected to be <class 'int'>, but value 24 with type <class 'str'> was found instead
您还可以解析来自pythondict
的数据。只需使用.from_dict()
函数即可:
fromdataclassesimportdataclassfromtyped_json_dataclassimportTypedJsonMixin@dataclassclassPerson(TypedJsonMixin):name:strage:intrequest_data_as_dict={'name':'Alice','age':'32'}alice=Person.from_dict(request_data_as_dict)# => TypeError: Person.age is expected to be <class 'int'>, but value 32 with type <class 'str'> was found instead
为自动映射设置映射模式
fromdataclassesimportdataclassfromtyped_json_dataclassimportTypedJsonMixin,MappingMode@dataclassclassPerson(TypedJsonMixin):person_name:strperson_age:intrequest_data_as_dict={'personName':'Alice','personAge':32}alice=Person.from_dict(request_data_as_dict,mapping_mode=MappingMode.SnakeCase)# => Person(person_name='Alice', person_age=32)
此映射模式对于在 camel case格式,但您希望您的对象是snake case并保持pep8 顺从。
限制和注意事项
只有init变量的数据类
支持具有init-only variables的数据类
是有限的。尽管to_dict
和to_json
将转换数据类,但是
结果dict或json字符串将不包含init-only变量,因为
它们的值在初始化后不可用。这也意味着
以后不能从dict或json字符串实例化数据类,因为
只有init变量是数据类'__init__
中的必需参数。
方法。TypedJsonMixin
检测仅使用init的数据类的用法
变量,当它转换为dict或json字符串时发出警告,并且
拒绝用仅初始化变量实例化数据类。
第一个解决方法是仅向init提供默认值 变量:
@dataclassclassPerson(TypedJsonMixin):person_name:InitVar[str]=''person_first_name:str=''person_last_name:str=''def__post_init__(self,person_name):ifperson_name:# Instantiated directlyself.person_first_name,self.person_last_name=person_name.split()# Call TypedJsonMixin __post_init__ methodsuper().__post_init__()
note:没有参数的实例化,例如Person()
,现在是
可能,尽管创建的实例随后将无效。
第二种解决方法是从数据类中删除init-only变量,然后
使用类方法执行__post_init__
实例化:
@dataclassclassPerson(TypedJsonMixin):person_first_name:strperson_last_name:str@classmethoddefcreate(cls,person_name):first_name,last_name=person_name.split()cls(first_name,last_name)
最后,如果不打算从dict或
json字符串,并且只调用to_dict
或to_json
方法,则
通过将warn_on_initvar=False
作为关键字传递,可以抑制警告
方法调用中的参数。