You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无重复访问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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 06:18:03