我正在尝试从类似于以下的代码中删除
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]
在这里不是有效类型的任何见解?
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
解析器,所有不兼容的东西都被拒绝。
这是一个带有此实现的游乐场。
不使用 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 类型不兼容。