TypedDict 不允许可选键?

Jak*_*ake 44 python pydantic typeddict

我想使用 pydantic 进行模式验证,并使用 TypedDict 来定义嵌套字典模式的一部分。但是,我意识到Optional如果在 TypedDict 类中指定它则不起作用。

我读到这个类将根据需要呈现所有键,并且使所有键都成为可选的方法是 at 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
Run Code Online (Sandbox Code Playgroud)

编辑

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

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]
Run Code Online (Sandbox Code Playgroud)

但遇到一条错误消息,指出 Dict 需要 2 个参数。显然 Dict 的工作方式不同,我无法像我希望的那样将其定义为一个类?

小智 64

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

class _trending(TypedDict):
    allStores: NotRequired[bool]
    category: str
    date: str
    average: List[int]
Run Code Online (Sandbox Code Playgroud)

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

如果你想与 Pydantic 一起使用TypedDict,你可以参考这篇文章

  • GitHub 中的 [typing_extensions](https://github.com/python/typing/blob/master/typing_extensions/README.rst)(未来的打字内容存在于此)[有](https://github.com/python /typing/blob/master/typing_extensions/src/typing_extensions.py) `NotRequired` 和 `Required`。**截至 22 年 2 月,pypi 只有 4.0.1,没有这些更改**。但无论如何,实验性功能意味着它们存在缺陷(参见“自我”问题),并且某些草稿确实被拒绝,因此可能会消失。 (9认同)
  • 导入什么很重要,尤其是在这种情况下。代码还应该从“typing_extensions”而不是“typing”导入“TypedDict”。 (6认同)
  • Python 3.10 中又如何呢? (3认同)

STe*_*kov 10

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

\n

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

\n

以下定义Main*是等效的:

\n
import sys\n# You may also pick one without version check, of course\nif sys.version_info < (3, 11):\n    from typing_extensions import TypedDict, Required, NotRequired\nelse:\n    from typing import TypedDict, Required, NotRequired\n\n\nclass Main1(TypedDict):\n    foo: int\n    bar: str\n    baz: NotRequired[int]\n    qux: NotRequired[str]\n\n\nclass Main2(TypedDict, total=False):\n    foo: Required[int]\n    bar: Required[str]\n    baz: int\n    qux: str\n\n\nclass _Main3(TypedDict):\n    foo: int\n    bar: str\n\nclass Main3(_Main3, total=False):\n    baz: int\n    qux: str\n\n\nclass _Main4(TypedDict, total=False):\n    baz: int\n    qux: str\n    \nclass Main4(_Main4):\n    foo: int\n    bar: str\n
Run Code Online (Sandbox Code Playgroud)\n

这是PEP 对整体性的解释

\n
\n

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

\n
\n

这是检查上述定义的示例:

\n
Main1(foo=1, bar=\'bar\', baz=2, qux=\'qux\')\nMain1(foo=1, bar=\'bar\', baz=2)\nMain1(foo=1, bar=\'bar\')\nMain1(foo=1, baz=2, qux=\'qux\')  # E: Missing key "bar" for TypedDict "Main1"  [typeddict-item]\nMain1(foo=1, bar=\'bar\', who=None)  # E: Extra key "who" for TypedDict "Main1"  [typeddict-item]\n\nMain2(foo=1, bar=\'bar\', baz=2, qux=\'qux\')\nMain2(foo=1, bar=\'bar\', baz=2)\nMain2(foo=1, bar=\'bar\')\nMain2(foo=1, baz=2, qux=\'qux\')  # E: Missing key "bar" for TypedDict "Main2"  [typeddict-item]\nMain2(foo=1, bar=\'bar\', who=None)  # E: Extra key "who" for TypedDict "Main2"  [typeddict-item]\n\nMain3(foo=1, bar=\'bar\', baz=2, qux=\'qux\')\nMain3(foo=1, bar=\'bar\', baz=2)\nMain3(foo=1, bar=\'bar\')\nMain3(foo=1, baz=2, qux=\'qux\')  # E: Missing key "bar" for TypedDict "Main3"  [typeddict-item]\nMain3(foo=1, bar=\'bar\', who=None)  # E: Extra key "who" for TypedDict "Main3"  [typeddict-item]\n\nMain4(foo=1, bar=\'bar\', baz=2, qux=\'qux\')\nMain4(foo=1, bar=\'bar\', baz=2)\nMain4(foo=1, bar=\'bar\')\nMain4(foo=1, baz=2, qux=\'qux\')  # E: Missing key "bar" for TypedDict "Main4"  [typeddict-item]\nMain4(foo=1, bar=\'bar\', who=None)  # E: Extra key "who" for TypedDict "Main4"  [typeddict-item]\n
Run Code Online (Sandbox Code Playgroud)\n

你可以在操场上摆弄这个

\n