如何对一般嵌套的TypedDict进行类型注释?



我试图从类似于以下代码中删除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或其他具有附加字段的TypedDicts(用于其他EventDicts),我无法提出兼容的TypedDict(mypy抱怨额外的键)。我认为Mapping[str, object]可能会在Any的地方工作,因为[A]任何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解析器,所有不兼容的都被拒绝。

这是一个游乐场。

最新更新