如何无重复访问Pydantic对象的嵌套可空属性且保留类型支持?
方案1:自定义带类型支持的BaseModel基类
无需修改原有字段定义,仅需将所有Pydantic模型的继承源改为自定义基类,即可同时兼容mypy检查与编辑器类型提示:
from typing import Optional, Any from pydantic import BaseModel as PydanticBaseModel class BaseModel(PydanticBaseModel): def get(self, attr: str, default: Optional[Any] = None) -> Any: if not hasattr(self, attr): return default value = getattr(self, attr) if isinstance(value, BaseModel): return value return value if value is not None else default
原有模型仅需替换继承的BaseModel即可,取值写法如下:
def get_country_code(p: Person) -> Optional[str]: address = p.get("address") if not address: return None country = address.get("country") if not country: return None return country.code
要实现更简洁的链式调用,可以配合通用工具函数:
from functools import reduce def safe_get(obj, *attrs: str): return reduce(lambda o, attr: o.get(attr) if hasattr(o, 'get') else None, attrs, obj) # 调用示例 def get_country_code(p: Person) -> Optional[str]: return safe_get(p, "address", "country", "code")
该方案完全不需要调整原有数据结构,所有类型推导逻辑保持原生支持。
方案2:原生model_dump方法+显式类型转换
如果不想侵入原有模型定义,可以直接使用Pydantic自带的序列化方法转字典,配合类型注解实现类型安全:
from typing import cast, Optional def get_country_code(p: Person) -> Optional[str]: p_dict = p.model_dump() code = p_dict.get("address", {}).get("country", {}).get("code") return cast(Optional[str], code)
该方案无额外依赖、无侵入修改,仅需在取值后增加显式类型声明即可满足mypy检查要求。
可选方案:第三方专用库
如果允许引入轻量依赖,可以使用专为Pydantic设计的pydantic-safe-get工具,原生支持类型推导,语法更接近你期望的可选链效果:
from pydantic_safe_get import safe_get def get_country_code(p: Person) -> Optional[str]: return safe_get(p).address.country.code()
调用时末尾加()即可触发取值,中间任意一层为None都会直接返回None,全程保留编辑器类型提示。
内容的提问来源于stack exchange,提问作者Martin Thoma
相关产品推荐
相关产品推荐

