如何定义同一个 TypedDict 的两个版本,一种是共有的,一种不是?

问题描述 投票:0回答:1

我正在尝试为 API 客户端定义两个版本的类型化字典,一个

total=False
用于部分更新路由输入,另一个
total=True
用于响应。任何具有字段子集的字典都可以作为输入有效,但输出字典必须包含所有字段。

我试过这个:

class PartialDict(TypedDict, total=False):
    name: str
    age: int

class FullDict(PartialDict, total=True):
    pass

但它不起作用,因为 Mypy 1.13 不会抱怨以下任何一个:

x: PartialDict = {}  # ok
y: FullDict = {}  # should fail

如果我反转继承并使

PartialDict
继承定义字段的
FullDict
,Mypy 会抱怨这两行:

mymodule/types.py:38: error: Missing keys ("name", "age") for TypedDict "PartialDict"  [typeddict-item]
mymodule/types.py:39: error: Missing keys ("name", "age") for TypedDict "FullDict"  [typeddict-item]

如何定义类型,例如

FullDict
必须具有所有键,但
PartialDict
可能不具有所有键?我想避免重复课程,因为我的现实世界字典有几十个键。

python python-typing
1个回答
0
投票

正如此评论中所述,您无法完全按照您的要求去做。

total
既不继承自
TypedDict
子类,也不追溯应用于其超类中的项目。

但是,如果我们回到这个问题,

任何具有字段子集的字典都可以作为输入有效,但输出字典必须包含所有字段。

这个是可以模仿的。这个想法是,输入在被修改时处于

total=False
状态,而输出仍然是非
total
,但与防止删除任何项目的类型联合。演示(mypy PlaygroundPyright Playground):

import typing as t
import collections.abc as cx

type FullDict[T: BaseTypedDict] = T | cx.Mapping[t.Any, t.Any]

class BaseTypedDict(t.TypedDict):
    pass

class PartialDict(t.TypedDict, total=False):
    name: str
    age: int

def populate(td: PartialDict, /) -> FullDict[PartialDict]:
    td["age"] = 20
    return td
>>> x: PartialDict = {"name": "John"}
>>> y: FullDict[PartialDict] = populate(x)
>>>
>>> del y["age"]   # Error: no method "__delitem__"
>>> y.pop("name")  # Error: no method "pop"
© www.soinside.com 2019 - 2024. All rights reserved.