Python运行时对任意键值对字典做类型提示与校验的实现方法
可行替代方案有两种,都不需要自行实现完整的dict子类:
方案1:返回只读映射视图,单独提供带校验的修改接口
这种方案无需额外依赖,从根源上禁止外部直接修改内部字典,所有修改操作必须走你暴露的带类型校验的方法:
from numbers import Number from typing import Dict, Mapping from types import MappingProxyType from typeguard import typechecked @typechecked class Foo: def __init__(self, data: Dict[str, Number]): self._data = dict(data) @property def data(self) -> Mapping[str, Number]: # 返回只读映射代理,外部直接修改会抛出类型错误,完全禁止非法修改 return MappingProxyType(self._data) def set_data_item(self, key: str, value: Number) -> None: # 所有修改必须走该方法,自动触发typeguard的类型校验 self._data[key] = value
使用效果:
bar = Foo({'x': 2, 'y': 3}) bar.data['z'] = 'test' # 直接抛出 TypeError: 'mappingproxy' object does not support item assignment bar.set_data_item('z', 4) # 正常运行 bar.set_data_item('z', 'test') # 触发typeguard校验错误
如果需要支持批量更新,只需额外加一个带@typechecked装饰的update_data方法即可:
def update_data(self, items: Dict[str, Number]) -> None: self._data.update(items)
方案2:使用第三方库封装好的运行时校验字典
如果不介意引入额外依赖,可以直接用pydantic的RootModel封装动态字典,所有字典修改操作都会自动触发运行时类型校验,无需自行实现任何接口:
from numbers import Number from pydantic import RootModel from typeguard import typechecked # 定义校验规则为键是字符串、值是数值的动态字典 ValidatedDict = RootModel[dict[str, Number]] @typechecked class Foo: def __init__(self, data: dict[str, Number]): self._data = ValidatedDict(data) @property def data(self) -> ValidatedDict: return self._data
使用效果:
bar = Foo({'x': 2, 'y': 3}) bar.data['z'] = 5 # 正常运行 bar.data['z'] = 'test' # 直接抛出pydantic.ValidationError校验错误
这种方案的使用体验和原生字典几乎一致,所有字典操作接口都已经被底层封装好了校验逻辑,无需额外适配。
内容的提问来源于stack exchange,提问作者s-m-e
相关产品推荐
相关产品推荐

