实用工具

API 包 路径: mcdreforged.api.utils

mcdreforged.utils.serializer.serialize(obj: Any) None | int | float | str | bool | list | dict[源代码]

一个工具函数,用于把任何对象序列化成一个 json 样式的 python 对象。在这里,拥有着 json 风格意味着其返回值可以直接作为参数传递给如 json.dumps()

序列化规则:

  • 不可变对象,包括 Noneintfloatstr 以及 bool,会被直接返回

  • listtuple 会被转换成一个所含元素均被序列化的 list 对象

  • dict 会被转换成一个所有键和值都被序列化的 dict

  • re.Pattern 会被转换为一个 str,其值为 re.Pattern.pattern。注意:如果 re.Pattern.pattern 返回了一个 bytes,它将会被转换成一个 utf8 编码的 str

  • 普通的对象会被转换成一个包含了其所有公开属性的 dict。键为属性的名字,值为序列化后的属性值

在 v2.8.0 版本加入: 如果对象是一个 Serializable,那么其属性的顺序将与注解中顺序的保持一致

在 v2.12.0 版本加入: 增加对基础类型的自定义子类、正则表达式对象(re.Pattern)的支持

参数:

obj – 被序列化的对象

返回:

序列化结果

mcdreforged.utils.serializer.deserialize(data: Any, cls: Type[T], *, error_at_missing: bool = False, error_at_redundancy: bool = False, missing_callback: Callable[[Any, Type, str], Any] | None = None, redundancy_callback: Callable[[Any, Type, str, Any], Any] | None = None) T[源代码]

一个工具函数,用于把一个 json 样式的 python 对象反序列化成给定的类

如果目标类包含嵌套的元素 / 属性,那么它们需要拥有详细的类型注解。这些元素 / 属性会被递归地反序列化

支持的目标类:

  • 不可变对象:Noneboolintfloat 以及 str

    • 输入数据的类应该等于目标类。没有隐式类型转换

    • 一个例外,float 还接受 int 作为输入数据

  • 标准容器:list, dict。需要用类型注解表示容器中的元素

    • typing.List, list:目标类应当形如 List[int]list[int] (python 3.9+)

    • typing.Dict, dict:目标类应当形如 Dict[str, bool]dict[str, bool] (python 3.9+)

  • 以下基础类型的自定义子类:intfloatstrboollist 以及 dict

  • typing 模块中的类型

  • 正则表达式对象(re.Pattern)。这时输入数据应该是一个 str

  • 普通类:这个类应当类型注解完善其所有属性,并且其构造函数应当可接受 0 个入参。类例子:

    class MyClass:
        some_str: str
        a_list: List[int]
    

    输入数据应该是一个 dict。dict 中的键和值对应着属性的名称以及序列化的属性值。dict 例子:

    {'some_str': 'foo', 'a_list': [1, 2, 3]}
    

    将使用 __setattr__ 设置对象的属性,非公开属性将被忽略

参数:
  • data – 被反序列化的 json 样式的对象

  • cls – 目标类,同时也是返回值的类型

关键字参数:
  • error_at_missing – 一个用于标识在反序列化一个对象的过程中,若对象存在未被赋值的属性,是否应该抛出异常的 flag。默认值为 false

  • error_at_redundancy – 一个用于标识在反序列化一个对象的过程中,若出现未知的输入属性,是否应该抛出异常的 flag。默认值为 false

  • missing_callback – 在反序列化对象过程中,发现对象存在未被赋值的属性时,调用的回调函数。该回调函数接受 3 个参数:此函数的 datacls 参数,以及对象缺失属性的名称

  • redundancy_callback – 在反序列化对象过程中,遇到未知的输入属性时,调用的回调函数。该回调函数接受 4 个参数:此函数的 datacls 参数,以及字典 data 中那个多余键值对的键和值

抛出:
  • TypeError – 若输入数据与目标类不匹配,或者目标类不在支持范围

  • ValueError – 如果输入数据非法,这包括 Literal 匹配失败,以及那些 kwargs 里的抛异常 flag 起了效果

返回:

一个类型为 cls 的对象

在 v2.7.0 版本加入: 增加对 typing.Literal 的支持

在 v2.12.0 版本加入: 增加对基础类型的自定义子类、正则表达式对象(re.Pattern)的支持

class mcdreforged.utils.serializer.Serializable(**kwargs)[源代码]

一个用于便捷序列化/反序列化的抽象类

继承它,并在你的子类中使用类型注解声明属性,你所需要做的就这么多

例子:

>>> class MyData(Serializable):
...     name: str
...     values: List[int]

>>> data = MyData.deserialize({'name': 'abc', 'values': [1, 2]})
>>> print(data.name, data.values)
abc [1, 2]

>>> data.serialize()
{'name': 'abc', 'values': [1, 2]}

>>> data = MyData(name='cde')
>>> data.serialize()
{'name': 'cde'}

Serializable 的嵌套也是支持的:

class MyStorage(Serializable):
    id: str
    best: MyData
    data: Dict[str, MyData]

你也可以在声明类型注解时声明属性的默认值,这样在反序列化的过程中,如果值缺失,则默认值的 copy.copy() 将会被赋值

>>> class MyArray(Serializable):
...     array: List[int] = [0]

>>> a = MyArray(array=[1])
>>> print(a.array)
[1]
>>> b, c = MyArray.deserialize({}), MyArray.deserialize({})
>>> print(b.array)
[0]

>>> b.array == c.array == MyArray.array
True
>>> b.array is not c.array is not MyArray.array
True

枚举类会被序列化为它的枚举成员名称:

>>> class Gender(Enum):
...     male = 'man'
...     female = 'woman'

>>> class Person(Serializable):
...     name: str = 'zhang_san'
...     gender: Gender = Gender.male

>>> data = Person.get_default()
>>> data.serialize()
{'name': 'zhang_san', 'gender': 'male'}
>>> data.gender = Gender.female
>>> data.serialize()
{'name': 'zhang_san', 'gender': 'female'}
>>> Person.deserialize({'name': 'li_si', 'gender': 'female'}).gender == Gender.female
True
__init__(**kwargs)[源代码]

使用给定的属性值创建一个 Serializable 对象

未指定的,在类型注解中含有默认值的属性,将被设为默认值的一个拷贝(copy.copy()

参数:

kwargs – 一个储存着用于设置属性的值的 dict。dict 的键为属性名,值为属性值

classmethod get_field_annotations() Dict[str, Type][源代码]

一个用来提取类的属性注解声明的辅助方法

只有公开属性会被提取。保护或私有的属性会被忽略

返回值会被缓存,以便于复用

返回:

一个储存了这个类声明的属性注解的 dict。其中键为属性名,值为对应属性的类型注解

在 v2.8.0 版本加入.

serialize() dict[源代码]

借助函数 serialize(),将自身序列化为一个 dict

classmethod deserialize(data: dict, **kwargs) Self[源代码]

借助函数 deserialize(),将一个 dict 反序列化为一个这个类的实例

如果存在缺失的属性,若可能,自动从类定义中拷贝默认值。见 __init__() 以了解更多的信息

classmethod get_default() Self[源代码]

构造一个使用默认值的这个类的实例

事实上,这个方法做的仅仅是不带参数地调用这个类的构造函数

merge_from(other: Self)[源代码]

将另一个实例的属性合并到当前实例中

备注

合并时,不会创建被合并属性的拷贝

如果你想要合并后的属性与另一个实例再无关联,你可以首先创建一个另一对象的 深拷贝,然后合并这个拷贝

参数:

other – 被合并属性的对象

在 v2.9.0 版本加入.

copy(*, deep: bool = True) Self[源代码]

创建一份此对象的拷贝。只有在类的注解中声明了的属性会被拷贝

默认情况下,创建深拷贝

关键字参数:

deep – 是否应该创建深拷贝。True:深拷贝,False:浅拷贝

在 v2.8.0 版本加入.

在 v2.9.0 版本加入: 添加 deep 关键字参数

validate_attribute(attr_name: str, attr_value: Any, **kwargs)[源代码]

一个将于反序列化期间,在设置属性值之前被调用的方法

你可以在这个方法中验证即将设置的属性值,并对期望之外的值抛出 ValueError 异常

参数:
  • attr_name – 将被设置的属性的名字

  • attr_value – 将被设置的属性值

关键字参数:

kwargs – 占位符

抛出:

ValueError – 若验证失败

在 v2.8.0 版本加入.

on_deserialization(**kwargs)[源代码]

一个将在反序列化完成后被调用的方法

你可以在这里做一些自定义的初始化操作

关键字参数:

kwargs – 占位符

在 v2.8.0 版本加入.