Decorators
@serde
@serde is a wrapper of @serialize and @deserialize decorators.
This code
@serde
class Foo:
...
is equivalent to the following code.
@deserialize
@serialize
@dataclass
class Foo:
...
@serde decorator does these for you:
- Add
@serializeand@deserializedecorators to a class - Add
@dataclassdecorator to a class if a class doesn't have@dataclass - You can pass both (de)serialize attributes to the decorator
serializerattribute is ignored in@deserializeanddeserializerattribute is ignored in@serialize
@serde(serializer=serializer, deserializer=deserializer)
@dataclass
class Foo:
...
NOTE:
@serdeactually works without @dataclass decorator, because it detects and add @dataclass to the declared class automatically. However, mypy will produceToo many argumentsorUnexpected keyword argumenterror. This is due to the mypy limitation.@serde class Foo: ...But if you use a PEP681 compliant type checker (e.g. pyright), you don't get the type error because pyserde supports PEP681 dataclass_transform
@serialize/@deserialize
@serialize and @deserialize are used by @serde under the hood. We recommend to use those two decorators in the following cases. Otherwise @serde is recommended.
- You only need either serialization or deserialization functionality
- You want to have different class attributes as below
@deserialize(rename_all = "snakecase")
@serialize(rename_all = "camelcase")
class Foo:
...
(de)serializing class without @serde
pyserde can (de)serialize dataclasses without @serde since v0.10.0. This feature is convenient when you want to use classes declared in external libraries or a type checker doesn't work with @serde decorator. See this example.
How does it work? It's quite simple that pyserde add @serde decorator if a class doesn't has it. It may take for a while for the first API call, but the generated code will be cached internally. So it won't be a problem. See the following example to deserialize a class in a third party package.
@dataclass
class External:
...
to_dict(External()) # works without @serde
Note that you can't specify class attributes e.g. rename_all in this case. If you want to add a class attribute to an external dataclass, there is a technique to do that by extending dataclass. See this example.
@dataclass
class External:
some_value: int
@serde(rename_all="kebabcase")
@dataclass
class Wrapper(External):
pass
How can I use forward references?
pyserde supports forward references. If you replace a nested class name with with string, pyserde looks up and evaluate the decorator after nested class is defined.
from __future__ import annotations # make sure to import annotations
@dataclass
class Foo:
i: int
s: str
bar: Bar # Bar can be specified although it's declared afterward.
@serde
@dataclass
class Bar:
f: float
b: bool
# Evaluate pyserde decorators after `Bar` is defined.
serde(Foo)
PEP563 Postponed Evaluation of Annotations
pyserde supports PEP563 Postponed evaluation of annotation.
from __future__ import annotations
from serde import serde
@serde
class Foo:
i: int
s: str
f: float
b: bool
def foo(self, cls: Foo): # You can use "Foo" type before it's defined.
print('foo')
See examples/lazy_type_evaluation.py for complete example.