TypedDict不允许可选键?



我想使用pydantic和TypedDict进行模式验证,以定义嵌套字典模式的一部分。然而,我意识到,如果在TypedDict类中指定Optional,它将不起作用。

我读到这个类将根据需要呈现所有的键,并且使它们都成为可选的一种方法是在total=False。但是,我只希望其中一个键是可选的,其他键是必需的。有没有办法克服这个限制?

from typing import List, Optional
from pydantic import BaseModel
from typing_extensions import TypedDict
class _trending(TypedDict):
allStores: Optional[bool] = False
category: str
date: str
average: List[int]
class RequestSchema(BaseModel):
storeId: str
trending: _trending

编辑

我以前尝试过这个,因为我认为它类似于嵌套列表。

from typing import List, Optional, Dict
from pydantic import BaseModel

class _trending(BaseModel):
allStores: Optional[bool] = False
category: str
date: str
average: List[int]
class RequestSchema(BaseModel):
storeId: str
trending: Dict[_trending]

但是面对一个错误消息说Dict需要2个参数。显然Dict的工作方式不同,我不能像我希望的那样把它定义为一个类?

从Python 3.11开始,根据PEP 655,您需要的是NotRequired:

class _trending(TypedDict):
allStores: NotRequired[bool]
category: str
date: str
average: List[int]

注意,您不应该在TypedDict中使用Optional,而只使用(Not)Required

如果您想在Pydantic中使用TypedDict,您可以参考这篇文章

我使用这个问题作为重复的目标,但注意到这里缺少另一个选项。

如果您不喜欢NotRequired(例如,如果您有许多必需的和许多可选的键,并且不想多次重复NotRequired)或不想麻烦typing_extensions(罕见情况),您可以调整total。

下列Main*的定义是等价的:

import sys
# You may also pick one without version check, of course
if sys.version_info < (3, 11):
from typing_extensions import TypedDict, Required, NotRequired
else:
from typing import TypedDict, Required, NotRequired

class Main1(TypedDict):
foo: int
bar: str
baz: NotRequired[int]
qux: NotRequired[str]

class Main2(TypedDict, total=False):
foo: Required[int]
bar: Required[str]
baz: int
qux: str

class _Main3(TypedDict):
foo: int
bar: str
class Main3(_Main3, total=False):
baz: int
qux: str

class _Main4(TypedDict, total=False):
baz: int
qux: str

class Main4(_Main4):
foo: int
bar: str

这是PEP对总体的解释:

total标志仅适用于TypedDict定义体中定义的项。继承的项不会受到影响,而是在定义它们的地方使用TypedDict类型的整体。这使得在单个TypedDict类型中组合必需键和非必需键成为可能。

下面是检查上面定义的例子:

Main1(foo=1, bar='bar', baz=2, qux='qux')
Main1(foo=1, bar='bar', baz=2)
Main1(foo=1, bar='bar')
Main1(foo=1, baz=2, qux='qux')  # E: Missing key "bar" for TypedDict "Main1"  [typeddict-item]
Main1(foo=1, bar='bar', who=None)  # E: Extra key "who" for TypedDict "Main1"  [typeddict-item]
Main2(foo=1, bar='bar', baz=2, qux='qux')
Main2(foo=1, bar='bar', baz=2)
Main2(foo=1, bar='bar')
Main2(foo=1, baz=2, qux='qux')  # E: Missing key "bar" for TypedDict "Main2"  [typeddict-item]
Main2(foo=1, bar='bar', who=None)  # E: Extra key "who" for TypedDict "Main2"  [typeddict-item]
Main3(foo=1, bar='bar', baz=2, qux='qux')
Main3(foo=1, bar='bar', baz=2)
Main3(foo=1, bar='bar')
Main3(foo=1, baz=2, qux='qux')  # E: Missing key "bar" for TypedDict "Main3"  [typeddict-item]
Main3(foo=1, bar='bar', who=None)  # E: Extra key "who" for TypedDict "Main3"  [typeddict-item]
Main4(foo=1, bar='bar', baz=2, qux='qux')
Main4(foo=1, bar='bar', baz=2)
Main4(foo=1, bar='bar')
Main4(foo=1, baz=2, qux='qux')  # E: Missing key "bar" for TypedDict "Main4"  [typeddict-item]
Main4(foo=1, bar='bar', who=None)  # E: Extra key "who" for TypedDict "Main4"  [typeddict-item]

你可以在playground

中修改这个

最新更新