如何键入注释一般嵌套的 TypedDict?

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

我正在尝试从类似于以下的代码中删除

Any
类型提示:

from typing import TypedDict, Any


class NestedDict(TypedDict):
    foo: str


class EventDict(TypedDict):
    nested: NestedDict


class BaseEventDict(TypedDict):
    nested: Any # this should accept NestedDict but also other TypedDicts which may contain additional fields


test_dict: EventDict = {
    "nested": {"foo": "abc"},
}


def print_dict(source_dict: BaseEventDict):
    print(source_dict)


print_dict(test_dict)

由于

nested
字段可以包含
NestedDict
或其他带有附加字段的
TypedDict
s(对于其他
EventDict
s),我无法想出兼容的
TypedDict
mypy
抱怨额外的钥匙)。我认为
Mapping[str, object]
可能会代替
Any
,因为 [A]ny TypedDict 类型与 Mapping[str, object] 一致。然而,
mypy
Argument 1 to "print_dict" has incompatible type "EventDict"; expected "BaseDict"
抱怨。有什么我可以使用而不是
Any
,这基本上禁用了检查?另外,关于为什么
Mapping[str, object]
在这里不是有效类型的任何见解?

python python-3.x mypy typeddict
2个回答
0
投票

TypedDict
字段是不变的,因为
TypedDict
是一个可变结构。 PEP589 中详细解释了其背后的原因。因此,要接受具有“某些
TypedDict
或与之兼容的任何内容”类型字段的
TypedDict
,您可以使用通用解决方案:

from __future__ import annotations
from typing import TypedDict, Generic, TypeVar

class NestedDict(TypedDict):
    foo: str

_T = TypeVar('_T', bound=NestedDict)

class BaseEventDict(Generic[_T], TypedDict):
    nested: _T # this should accept NestedDict but also other TypedDicts which may contain additional fields

BaseEventDict
使用其字段类型进行参数化,该类型绑定到
NestedDict
- 这样
T
只能用与
NestedDict
兼容的东西替换。让我们检查一下:

class GoodNestedDict(TypedDict):
    foo: str
    bar: str

class BadNestedDict(TypedDict):
    foo: int


class EventDict(TypedDict):
    nested: NestedDict

class GoodEventDict(TypedDict):
    nested: GoodNestedDict
    
class BadEventDict(TypedDict):
    nested: BadNestedDict


# Funny case: lone TypeVar makes sense here
def print_dict(source_dict: BaseEventDict[_T]) -> None:
    print(source_dict)

test_dict: EventDict = {
    "nested": {"foo": "abc"},
}
good_test_dict: GoodEventDict = {
    "nested": {"foo": "abc", "bar": "bar"},
}
bad_test_dict: BadEventDict = {
    "nested": {"foo": 1},
}

print_dict(test_dict)
print_dict(good_test_dict)
print_dict(bad_test_dict)  # E: Value of type variable "_T" of "print_dict" cannot be "BadNestedDict"  [type-var]

在此设置中

print_dict
也很有趣:您不能使用上限,因为字段类型是不变的,因此带有界限(与以前相同)的单个
TypeVar
可以拯救。任何与
NestedDict
兼容的东西都被接受为
_T
解析器,所有不兼容的东西都被拒绝。

这是一个带有此实现的游乐场


-2
投票

不使用 Any,你可以定义一个新的 BaseDict 类型,它接受任何 TypedDict,只要它的嵌套字段是 NestedDict 类型:

from typing import Mapping, Type, Union, TypedDict


class NestedDict(TypedDict):
    foo: str


class EventDict(TypedDict):
    nested: NestedDict


class BaseDict(TypedDict):
    nested: Union[NestedDict, Type[TypedDict[object, object]]]


test_dict: EventDict = {
    "nested": {"foo": "abc"},
}


def print_dict(source_dict: BaseDict):
    print(source_dict)


print_dict(test_dict)

BaseDict 类型使用 Union 来接受 NestedDict 或任何 TypedDict,其中嵌套字段的类型为 NestedDict。为此,Type 函数用于引用 TypedDict 类而不实例化它。

关于您关于 Mapping[str, object] 的问题,在这种情况下它不是有效类型,因为它太通用了。它将允许字典中的任何键值对,而不仅仅是嵌套字段。这与具有特定结构的 EventDict 类型不兼容。

© www.soinside.com 2019 - 2024. All rights reserved.