Python中如何验证对象是否符合 typing.Dict[str, int] 类型?
主要想做的就是
- 拿到一个对象, cast 出来这个对象是否符合 typing 里那些奇怪类型, Union Optional 等, 尤其是 Dict[str, int] 时候要判断每一个 key value 的类型
- 拿到不符合的类型时候, 自动转换一下, 比如 '1.1' 需要 float 类型, 自动转成 1.1
找过一大些资料都失败了, 目前结论如下
-
mypy 没法直接看源码, 然后看文档也没找到那种代码里 import mypy 然后做 cast 的功能
-
typing.cast 在标准库那个是预留给 linter 用的, 实际用不上
-
目前已经尝试过
__origin__和__args__来做了, 效果还算不错, 但是感觉自己一点点拆包有点傻, 尤其是自己把不符合的先_alias, 然后对_GenericAlias做上述俩魔术方法, 遇到了_SpecialForm直接凉
mypy 官网提到的 MonkeyType (Python 3) and PyAnnotate (type comments only). 还没试
Python中如何验证对象是否符合 typing.Dict[str, int] 类型?
1、你是想要做什么呢?如果是想要在每个函数的入口这么干,就太影响程序的性能了。
2、如果是想要对用户的输入(比如 API parameters )进行验证,可以使用 pydantic。
https://pydantic-docs.helpmanual.io/
from typing import Dict, get_type_hints, get_origin, get_args
import inspect
def validate_dict_type(obj, expected_type) -> bool:
"""
验证对象是否符合指定的 typing.Dict 类型
Args:
obj: 要验证的对象
expected_type: 期望的类型,如 Dict[str, int]
Returns:
bool: 是否符合类型
"""
# 1. 首先检查是否是字典类型
if not isinstance(obj, dict):
return False
# 2. 获取泛型参数
origin = get_origin(expected_type)
args = get_args(expected_type)
# 3. 检查是否是 Dict 类型
if origin is not Dict or len(args) != 2:
return False
key_type, value_type = args
# 4. 验证所有键值对
for key, value in obj.items():
# 验证键类型
if key_type is not type(None) and not isinstance(key, key_type):
return False
# 验证值类型
if value_type is not type(None) and not isinstance(value, value_type):
return False
return True
# 使用示例
if __name__ == "__main__":
# 测试用例
test_cases = [
({"a": 1, "b": 2}, Dict[str, int], True),
({1: "a", 2: "b"}, Dict[str, int], False), # 键不是字符串
({"a": "hello", "b": "world"}, Dict[str, int], False), # 值不是整数
({"a": 1, "b": 2.5}, Dict[str, int], False), # 值包含浮点数
([1, 2, 3], Dict[str, int], False), # 不是字典
({}, Dict[str, int], True), # 空字典
({"a": 1, "b": None}, Dict[str, int], False), # 值包含None
]
for obj, expected_type, should_pass in test_cases:
result = validate_dict_type(obj, expected_type)
status = "✓" if result == should_pass else "✗"
print(f"{status} {obj} -> {expected_type}: {result}")
这个实现的核心思路是:先检查对象是否是字典,然后通过get_origin()和get_args()提取泛型参数,最后遍历验证每个键值对的类型。注意处理边缘情况如空字典和None类型。
简单来说:用get_origin()和get_args()提取类型参数再逐个验证。
pydantic 看过了, 不过当时只看了它的那些 BaseSchema 用法, 就是自定义, 不过我要处理的是 typing 里的内置类型(或者复合类型)
我只是想对某些值做一下类型校验, mypy 上没找到, 官方文档也是说 typing.cast 太影响性能所以什么都不做, 只留给 linters 做猴子补丁
我看看那些 mypy 以外的有没有什么办法吧
好吧, 我傻了, 还是用 pydantic 吧
说白了其实我就是想知道下 typing 里那么多复杂的类型, 怎么做验证, 学习的目的
那是给 IDE 用的
我就是打算研究研究有什么自带的内置方法可以让我验证么, 毕竟 isinstance 是报错的
我先研究研究用 type 动态构造 BaseModel 子类
from pydantic import BaseModel
import typing
import inspect
def test(a: int, b: typing.Dict[str, int]):
pass
sigs = inspect.signature(test)
kwargs = {p.name: p.annotation for p in sigs.parameters.values()}
看了 pydantic 源码,他是这么干的
https://gist.github.com/Trim21/910601a17fbeaa07bd203a93afce6131
我没仔细研究 field.validate 的第二个参数是干啥用的
我之前第一选择是 pydantic , 后来因为看文档不仔细给弃用了, 结果仔细看了下文档, 觉得真香, 把我 3 个多小时写的垃圾全弃用了…
gist 我这边污染打不开, 好容易换 192.30.253.118 结果说 404…
#8
import pydantic.validators
from pydantic.fields import Field
from typing import Dict, Any
field = Field(name=‘d’,
type_=Dict[str, int],
class_validators=None,
model_config=pydantic.BaseConfig)
raw, errs = field.validate({‘key’: ‘value’}, {‘a’: ‘1’}, loc=‘loc’)
print(raw, errs)
# {‘key’: ‘value’}, [<pydantic.error_wrappers.ErrorWrapper object at 0x00000199F1B9BE58>]
感谢,找了半天没找到,vscode 对这些相对路径的跳转太差了。。。已解决
你们思维真是死板啊
这种标准类型直接 jsonschema 校验不就完了 非要纠结到语言的新功能上
感谢提醒, 我都快忘了那个库了, 刚听说 jsonschema 可以支持 Union Optional Dict[str,int]。
呃,show me your code?
只处理过简单的,要__annotations__属性或者 inspect.signature
我上面提到的 __origin__ 和 __args__ 就是…
改用 pydantic 搞定很多类型严重和转换问题.


