我试图从类似于以下代码中删除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]任何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
解析器,所有不兼容的都被拒绝。
这是一个游乐场。