如何在 Python 3.6 中使用具有不同值类型的 Dict 进行静态类型检查?
How to use static type checking using Dict with different value types in Python 3.6?
尝试在 Python 代码中使用静态类型,因此 mypy
可以帮助我解决一些隐藏的错误。使用单个变量非常简单
real_hour: int = lower_hour + hour_iterator
更难与列表和字典一起使用,需要导入额外的 typing
库:
from typing import Dict, List
hour_dict: Dict[str, str] = {"test_key": "test_value"}
但主要问题是如何将它与具有不同值类型的 Dicts 一起使用,例如:
hour_dict = {"test_key": "test_value", "test_keywords": ["test_1","test_2"]}
如果我不对此类词典使用静态类型 - mypy 会向我显示错误,例如:
len(hour_dict['test_keywords'])
- Argument 1 to "len" has incompatible type
那么,我的问题是:如何将静态类型添加到此类词典中? :)
您需要某种类型的 Union
。
from typing import Dict, List, Union
# simple str values
hour_dict: Dict[str, str] = {"test_key": "test_value"}
# more complex values
hour_dict1: Dict[str, Union[str, List[str]]] = {
"test_key": "test_value",
"test_keywords": ["test_1","test_2"]
}
一般来说,当您需要 "either this or that," 时,您就需要 Union
。在这种情况下,您的选项是 str
和 List[str]
。
有几种方法可以解决这个问题。例如,您可能想要定义类型名称以简化内联类型。
OneOrManyStrings = Union[str, List[str]]
hour_dict2: Dict[str, OneOrManyStrings] = {
"test_key": "test_value",
"test_keywords": ["test_1","test_2"]
}
为了简单性、并行性和规律性,我可能还会建议将所有 dict
值设为纯 List[str]
,即使只有一项。这将允许您始终获取值的 len()
,而无需事先进行类型检查或保护条件。但这些点都是细节和调整。
虽然使用 Union
确实是一种方法,但更精确的解决方案是使用(目前处于实验阶段)TypedDict
类型,它允许您为每个字符串键分配特定类型.
为了使用这种类型,您必须首先使用 pip 安装 mypy_extensions
第 3 方库。然后您可以执行以下操作:
from typing import List
from mypy_extensions import TypedDict
MyDictType = TypedDict('MyDictType', {
'test_key': str,
'test_keywords': List[str],
})
hour_dict: MyDictType = {
"test_key": "test_value",
"test_keywords": ["test_1","test_2"]
}
请注意,我们需要明确表示 hour_dict
属于 MyDictType
类型。一种稍微更简洁的方法是使用 MyDictType
作为构造函数——在运行时,MyDictType(...)
完全等同于 dict(...)
,这意味着下面的代码与上面的代码行为完全相同:
hour_dict = MyDictType(
test_key="test_value",
test_keywords=["test_1","test_2"]
)
最后,请注意使用 TypedDict 有一些限制:
- 仅当字典将包含编译时已知类型的特定键时才有用——如果您希望使用真正动态的字典,则应使用常规
Dict[...]
。
- 键必须都是字符串。
- 目前,这种类型只能被 mypy 理解(尽管我知道有计划最终将 TypedDict 添加到 PEP 484 中,一旦它经过更多的实战测试,这意味着将需要任何符合 PEP 484 的类型检查器支持一下)。
(TypedDict
的设计目的是为了在编写 serialization/deserialization 逻辑时更容易使用 JSON blobs/dicts,这就是这些限制的原因。)
尝试在 Python 代码中使用静态类型,因此 mypy
可以帮助我解决一些隐藏的错误。使用单个变量非常简单
real_hour: int = lower_hour + hour_iterator
更难与列表和字典一起使用,需要导入额外的 typing
库:
from typing import Dict, List
hour_dict: Dict[str, str] = {"test_key": "test_value"}
但主要问题是如何将它与具有不同值类型的 Dicts 一起使用,例如:
hour_dict = {"test_key": "test_value", "test_keywords": ["test_1","test_2"]}
如果我不对此类词典使用静态类型 - mypy 会向我显示错误,例如:
len(hour_dict['test_keywords'])
- Argument 1 to "len" has incompatible type
那么,我的问题是:如何将静态类型添加到此类词典中? :)
您需要某种类型的 Union
。
from typing import Dict, List, Union
# simple str values
hour_dict: Dict[str, str] = {"test_key": "test_value"}
# more complex values
hour_dict1: Dict[str, Union[str, List[str]]] = {
"test_key": "test_value",
"test_keywords": ["test_1","test_2"]
}
一般来说,当您需要 "either this or that," 时,您就需要 Union
。在这种情况下,您的选项是 str
和 List[str]
。
有几种方法可以解决这个问题。例如,您可能想要定义类型名称以简化内联类型。
OneOrManyStrings = Union[str, List[str]]
hour_dict2: Dict[str, OneOrManyStrings] = {
"test_key": "test_value",
"test_keywords": ["test_1","test_2"]
}
为了简单性、并行性和规律性,我可能还会建议将所有 dict
值设为纯 List[str]
,即使只有一项。这将允许您始终获取值的 len()
,而无需事先进行类型检查或保护条件。但这些点都是细节和调整。
虽然使用 Union
确实是一种方法,但更精确的解决方案是使用(目前处于实验阶段)TypedDict
类型,它允许您为每个字符串键分配特定类型.
为了使用这种类型,您必须首先使用 pip 安装 mypy_extensions
第 3 方库。然后您可以执行以下操作:
from typing import List
from mypy_extensions import TypedDict
MyDictType = TypedDict('MyDictType', {
'test_key': str,
'test_keywords': List[str],
})
hour_dict: MyDictType = {
"test_key": "test_value",
"test_keywords": ["test_1","test_2"]
}
请注意,我们需要明确表示 hour_dict
属于 MyDictType
类型。一种稍微更简洁的方法是使用 MyDictType
作为构造函数——在运行时,MyDictType(...)
完全等同于 dict(...)
,这意味着下面的代码与上面的代码行为完全相同:
hour_dict = MyDictType(
test_key="test_value",
test_keywords=["test_1","test_2"]
)
最后,请注意使用 TypedDict 有一些限制:
- 仅当字典将包含编译时已知类型的特定键时才有用——如果您希望使用真正动态的字典,则应使用常规
Dict[...]
。 - 键必须都是字符串。
- 目前,这种类型只能被 mypy 理解(尽管我知道有计划最终将 TypedDict 添加到 PEP 484 中,一旦它经过更多的实战测试,这意味着将需要任何符合 PEP 484 的类型检查器支持一下)。
(TypedDict
的设计目的是为了在编写 serialization/deserialization 逻辑时更容易使用 JSON blobs/dicts,这就是这些限制的原因。)