我想使用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
中修改这个