Dataclasses 和 TypedDicts 之间的类型检查转换

Tom*_*han 5 python mypy python-dataclasses typeddict

我有一堆@dataclasses 和一堆对应的TypedDicts,我想促进它们之间的平滑和类型检查转换。

例如,考虑

from dataclasses import dataclass
from typing_extensions import TypedDict

@dataclass
class Foo:
    bar: int
    baz: int
   
    @property
    def qux(self) -> int:
        return bar + baz

class SerializedFoo(TypedDict):
    bar: int
    baz: int
    qux: int
Run Code Online (Sandbox Code Playgroud)

要创建序列化函数,我可以编写类似

def serialize(foo: Foo) -> SerializedFoo:
    return SerializedFoo(
        bar=foo.bar,
        baz=foo.baz,
        qux=foo.qux,
    )
Run Code Online (Sandbox Code Playgroud)

但是对于很多类型这样做变得乏味,而且每次更新类型时,我还必须更新序列化功能。

我也可以做类似的事情

def serialize(foo: Foo) -> SerializedFoo:
    return SerializedFoo(**dataclasses.asdict(foo))
Run Code Online (Sandbox Code Playgroud)

但这不会进行类型检查;mypy抱怨它Expected keyword arguments, {...}, or dict(...) in TypedDict constructor

从理论上讲,足够聪明的类型检查器应该有可能知道数据类具有初始化类型字典所需的属性,但是当然,使用asdict使得这在实践中是不可能的。

有没有更好的方法将 a 转换dataclassTypedDict具有相应字段的 a ,这让我都可以让类型检查器在出现问题时告诉我,而不必在转换中输入每个字段?

小智 6

TypedDict运行时的常规字典,不是真正的类,不执行任何类型检查,仅用于类型提示目的。因此,您可以简单地使用(此处的typing.cast文档):

import dataclasses
from typing import cast

def serialize(foo: Foo) -> SerializedFoo:
    return cast(SerializedFoo, dataclasses.asdict(foo))
Run Code Online (Sandbox Code Playgroud)

会让Python 类型检查器高兴。

dacite你也可以去图书馆看看。对于这样的东西,它有一些漂亮的东西,但又没有marshmallow. asdict它允许在其/函数中进行某种类型的转换from_dict

  • 我在上面的评论中分享的链接是一个在服务器上运行 mypy 的网站,因此您可以尝试那里的解决方案,您会发现 MyPy 对此非常满意:) (2认同)