python - 任何用于序列化属性的 cattrs 解决方案都使用不同的名称?

标签 python json-deserialization python-attrs

我试图找到类似于 java Jackson ObjectMapper 的解决方案可以将 python 对象序列化/反序列化为 json。并发现

  • cattrs最接近我需要的。但它不能像在 json 中使用 firstName 但在反序列化对象中使用 first_name 那样进行属性映射。

  • attrs-serde可以做属性映射,不能做递归反序列化。

这个问题可以用这个例子来说明,

import attr
import cattr
from attrs_serde import serde

name_path = ["contact", "personal", "Name"]
phone_path = ["contact", "Phone"]


@serde
@attr.s(auto_attribs=True, frozen=True)
class Name:
    first: str
    last: str


@serde
@attr.s(auto_attribs=True, frozen=True)
class Person:
    name: Name = attr.ib(metadata={"to": name_path, "from": name_path})
    phone: str = attr.ib(metadata={"to": phone_path, "from": phone_path})


person_json = {"contact": {"personal": {"Name": {"first": "John", "last": "Smith"}}, "Phone": "555-112233"}}

# XXX: to/from only works on serde
p = Person(name=Name(first="John", last="Smith"), phone="555-112233")
print(p.to_dict())
# {'contact': {'personal': {'Name': {'first': 'John', 'last': 'Smith'}}, 'Phone': '555-112233'}}
p1 = Person.from_dict(person_json)
print(f"p1={p1}")
# p1=Person(name={'first': 'John', 'last': 'Smith'}, phone='555-112233')

# XXX: nested only works on cttrs
person = {"Name": {"First": "John", "Last": "Smith"}, "Phone": "555-112233"}
converter = cattr.Converter()
converter.register_structure_hook(
    Person, lambda d, _: Person(name=converter.structure(d["Name"], Name), phone=d.get("Phone"))
)
converter.register_structure_hook(Name, lambda d, _: Name(first=d["First"], last=d.get("Last")))

p2 = converter.structure(person, Person)
print(p2)
assert p == p2

print(converter.unstructure(p2))
# {'name': {'first': 'John', 'last': 'Smith'}, 'phone': '555-112233'}
# {"contact": {"personal": {"name": "John"}, "phone": "555-112233"}}

使用 cattr 的任何更优雅的解决方案?

最佳答案

你可以使用驼峰来进行大小写转换

import humps

import cattr

class CAttrConverter:

    converter = cattr.Converter()

    def __init__(self):
        """
        structure hook for load
        unstructure hook for dump
        """

    def load(self, params, data_cls, camel_to_snake=True):
        """
        :param params: params, mostly from front end
        :param data_cls:
        :param camel_to_snake: need to convert from camel style to snake style
        """
        if camel_to_snake:
            params = humps.depascalize(params)
        return self.converter.structure(params, data_cls)

    def dump(self, data, snake_to_camel=False):
        """
        :param data:
        :param snake_to_camel: dump as camel case
        """
        result: dict = self.converter.unstructure(data)
        if snake_to_camel:
            result = humps.camelize(result)

        return result

关于python - 任何用于序列化属性的 cattrs 解决方案都使用不同的名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59494486/

相关文章:

python - 在 python 中重命名 elif

python - 根据年月算术生成文件名列表

android - 反序列化Gson中的有序列表

json - Rust Serde - 是否可以将两种不同布局中的 json 数据映射回单个结构?

Python attrs - 父类(super class)中的位置属性而子类中可选

python - 如何(自动)配置存储库/项目脚手架 Azure DevOps/GitHub?

python - 使用 Networkx 重叠社区检测

java - Gson反序列化返回一个包含null的Object

python - 在 python attrs 类中,如何用我自己的重写生成的 __init__

python - 如何避免 __init__ 中的 "self.x = x; self.y = y; self.z = z"模式?