有没有使用不同名称序列化属性的cattrs解决方案?

2024-05-12 19:46:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图找到一个类似于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还有更优雅的解决方案吗


Tags: pathnamefromcontactphonejohnconverterperson