I have a bunch of @dataclass
es and a bunch of corresponding TypedDict
s, and I want to facilitate smooth and type-checked conversion between them.
For example, consider
from dataclasses import dataclass
from typing_extensions import TypedDict
@dataclass
class Foo:
bar: int
baz: int
@property
def qux(self) -> int:
return self.bar + self.baz
class SerializedFoo(TypedDict):
bar: int
baz: int
qux: int
To create a serialization function, I can write something like
def serialize(foo: Foo) -> SerializedFoo:
return SerializedFoo(
bar=foo.bar,
baz=foo.baz,
qux=foo.qux,
)
but doing this for many types becomes tedious, and every time I update the types, I also have to update the serialization function.
I can also do something like
import dataclasses
def serialize(foo: Foo) -> SerializedFoo:
return SerializedFoo(**dataclasses.asdict(foo))
but this doesn't type check; mypy
complains that it Expected keyword arguments, {...}, or dict(...) in TypedDict constructor
.
Theoretically, it should be possible for a sufficiently smart type-checker to know that the dataclass has the properties needed to initialize the typed dictionary, but of course the usage of asdict
makes this impossible in practice.
Is there a better way to convert a dataclass
to a TypedDict
with corresponding fields, that lets me both have the type checker tell me when something is wrong, and not have to type out every field in the conversion?
The motivation here is simplicity. TypedDict type definitions could plausibly used to perform runtime type checking of dictionaries. For example, they could be used to validate that a JSON object conforms to the schema specified by a TypedDict type.
TypedDict objects are regular dictionaries at runtime, and TypedDict cannot be used with other dictionary-like or mapping-like classes, including subclasses of dict. There is no way to add methods to TypedDict types. The motivation here is simplicity. TypedDict type definitions could plausibly used to perform runtime type checking of dictionaries.
In C++, it can be done by two ways: Converting by assignment: This is done by explicitly defining the required type in front of the expression in parenthesis. This can be also considered as forceful casting. Syntax: (type) expression. where type indicates the data type to which the final result is converted. Example:
There are two types of type conversion: Implicit Type Conversion Also known as ‘automatic type conversion’. Done by the compiler on its own, without any external trigger from the user. Generally takes place when in an expression more than one data type is present.
TypedDict
is a regular dict at runtime, not a real class, doesn't do any type-checking, and is only for type hinting purposes. So, you can simply use typing.cast
(docs here):
import dataclasses
from typing import cast
def serialize(foo: Foo) -> SerializedFoo:
return cast(SerializedFoo, dataclasses.asdict(foo))
which will make Python type-checkers happy.
You could also check out the dacite
library. It has some nifty things for stuff like this without the overkill of marshmallow
. It allows some kind of type casting in its asdict
/from_dict
functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With