如何在Pydantic泛型基类中实现泛型类型的默认工厂?
Pydantic泛型模型字段默认工厂的实现方案
问题场景
想要创建一个泛型基模型,让字段默认使用对应类型的默认工厂,编写了如下代码:
from pydantic import BaseModel, Field from pydantic.generics import GenericModel, Generic from typing import TypeVar, Generic, Optional T = TypeVar("T") class Material(GenericModel, Generic[T]): value: T = Field(default_factory=T) Material[float](value=1) Material[float](value="1 ") Material[Optional[float]]()
运行时触发如下错误:
Traceback (most recent call last): File "/home/tom/.config/JetBrains/PyCharm2022.2/scratches/tmp.py", line 14, in <module> Material[Optional[float]]() File "pydantic/main.py", line 340, in pydantic.main.BaseModel.__init__ File "pydantic/main.py", line 1066, in pydantic.main.validate_model File "pydantic/fields.py", line 439, in pydantic.fields.ModelField.get_default TypeError: 'TypeVar' object is not callable
问题:是否可以为泛型类型设置默认工厂?
问题根源
直接将TypeVar对象T传给default_factory不可行:
- 当实例化
Material[Optional[float]]时,T绑定的是Optional[float],这是一个类型注解而非可调用的工厂函数 - 即使是
float这类可调用的基本类型,default_factory=T的写法在模型定义阶段仍会将T视为未绑定的TypeVar对象,无法正确解析
可行实现方案
通过动态解析泛型类型参数,自定义默认生成逻辑,代码如下:
from pydantic import BaseModel, Field from pydantic.generics import GenericModel, Generic from typing import TypeVar, Optional, get_args, get_origin T = TypeVar("T") class Material(GenericModel, Generic[T]): value: T = Field(default_factory=lambda self: self._get_default()) def _get_default(self): # 获取当前模型绑定的泛型类型 bound_type = get_args(self.__orig_bases__[0])[0] type_origin = get_origin(bound_type) # 处理Optional类型,返回None if type_origin is Optional: return None # 基本类型调用自身生成默认值(如float()→0.0,str()→"") try: return bound_type() except TypeError: # 复杂类型可根据需求返回自定义默认值,此处返回None return None # 测试验证 print(Material[float](value=1)) # Material(value=1.0) print(Material[float](value="1 ")) # Material(value=1.0) print(Material[Optional[float]]()) # Material(value=None) print(Material[str]()) # Material(value='')
核心逻辑说明
- 解析泛型绑定类型:通过
self.__orig_bases__获取当前实例绑定的泛型参数,再用get_args提取具体类型 - 处理Optional类型:利用
get_origin识别Optional类型,直接返回None - 适配基本类型:对可调用的基本类型(如
int/float/str),调用自身生成默认值;对不可调用的复杂类型,返回自定义默认值
内容的提问来源于stack exchange,提问作者Tom McLean
相关产品推荐
相关产品推荐

