news 2026/8/19 18:25:52

Pydantic中的default_factory详解:初学者必看指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Pydantic中的default_factory详解:初学者必看指南

前言

在使用Pydantic进行数据验证和设置管理时,你可能会遇到一个常见的问题:如何正确设置包含列表、字典或自定义对象的默认值?这时候default_factory就派上用场了。本文将从零开始,用通俗易懂的方式为初学者介绍这个重要概念。

什么是default_factory?

default_factory是Pydantic中Field的一个参数,用于动态创建默认值。简单来说,它接受一个函数(或类),每次需要默认值时就调用这个函数来创建一个全新的对象。

为什么需要default_factory?

问题场景:可变对象的陷阱

让我们先看一个常见的错误:

frompydanticimportBaseModel,FieldfromtypingimportList# 错误的写法classUserConfig(BaseModel):name:str="默认用户"hobbies:List[str]=Field(default=[])# 危险!# 创建两个用户user1=UserConfig()user2=UserConfig()# 给第一个用户添加爱好user1.hobbies.append("游戏")print(f"用户1的爱好:{user1.hobbies}")# ['游戏']print(f"用户2的爱好:{user2.hobbies}")# ['游戏'] ← 问题出现了!

问题:两个不同的用户实例竟然共享了同一个爱好列表!这是因为default=[]创建的是同一个列表对象,所有实例都指向它。

解决方案:使用default_factory

frompydanticimportBaseModel,FieldfromtypingimportList# 正确的写法classUserConfig(BaseModel):name:str="默认用户"hobbies:List[str]=Field(default_factory=list)# 每次调用list()创建新列表# 创建两个用户user1=UserConfig()user2=UserConfig()# 给第一个用户添加爱好user1.hobbies.append("游戏")print(f"用户1的爱好:{user1.hobbies}")# ['游戏']print(f"用户2的爱好:{user2.hobbies}")# [] ← 正确!

default vs default_factory 对比

特性defaultdefault_factory
用途静态默认值动态默认值
适用场景不可变对象(字符串、数字等)可变对象(列表、字典、自定义类等)
创建时机类定义时创建一次每次实例化时创建
是否共享是(可变对象有风险)否(每次都是新对象)

代码示例对比

fromdatetimeimportdatetimefrompydanticimportBaseModel,FieldclassConfigExample(BaseModel):# 适合用 default 的场景app_name:str=Field(default="我的应用")version:str=Field(default="1.0.0")debug:bool=Field(default=False)# 适合用 default_factory 的场景tags:list=Field(default_factory=list)settings:dict=Field(default_factory=dict)created_at:datetime=Field(default_factory=datetime.now)

嵌套模型中的default_factory

在复杂应用中,我们经常需要嵌套模型:

frompydanticimportBaseModel,FieldclassDatabaseConfig(BaseModel):host:str="localhost"port:int=5432database:str="myapp"classAppConfig(BaseModel):app_name:str="我的应用"# 错误写法# database: DatabaseConfig = Field(default=DatabaseConfig) # 传递类本身# 也是错误的# database: DatabaseConfig = Field(default=DatabaseConfig()) # 所有实例共享# 正确写法database:DatabaseConfig=Field(default_factory=DatabaseConfig)# 测试app1=AppConfig()app2=AppConfig()print(app1.databaseisapp2.database)# False - 不同的实例

高级用法:自定义工厂函数

default_factory可以接受任何可调用对象:

frompydanticimportBaseModel,Fieldfromdatetimeimportdatetime,timedeltadefcreate_default_settings():"""自定义工厂函数"""return{"theme":"dark","language":"zh-CN","timeout":30}deffuture_time():"""返回一小时后的时间"""returndatetime.now()+timedelta(hours=1)classUserProfile(BaseModel):username:str# 使用自定义函数settings:dict=Field(default_factory=create_default_settings)# 使用lambda表达式permissions:list=Field(default_factory=lambda:["read","write"])# 使用其他函数expires_at:datetime=Field(default_factory=future_time)# 测试user=UserProfile(username="张三")print(user.settings)# {'theme': 'dark', 'language': 'zh-CN', 'timeout': 30}print(user.permissions)# ['read', 'write']print(user.expires_at)# 一小时后的时间

实现原理简析

default_factory的工作原理其实很简单:

# 简化的内部逻辑classField:def__init__(self,default_factory=None):self.default_factory=default_factorydefget_default_value(self):ifself.default_factory:returnself.default_factory()# 调用函数创建新对象returnNone# 当你创建模型实例时# model = MyModel()# 内部会调用 field.get_default_value() 来获取默认值

常见错误和解决方案

错误1:混淆default和default_factory

# 错误tags:list=Field(default=list)# 传递了函数对象,不是调用结果# 正确tags:list=Field(default_factory=list)# 传递函数,让Pydantic调用

错误2:在default_factory中传递实例

# 错误config:DatabaseConfig=Field(default_factory=DatabaseConfig())# 传递了实例# 正确config:DatabaseConfig=Field(default_factory=DatabaseConfig)# 传递类

错误3:忘记处理可变默认值

# 危险的写法defcreate_user(hobbies=[]):# 默认参数陷阱return{"hobbies":hobbies}# 正确的写法defcreate_user(hobbies=None):ifhobbiesisNone:hobbies=[]return{"hobbies":hobbies}

实际应用场景

场景1:配置管理

frompydantic_settingsimportBaseSettingsfrompydanticimportFieldclassDatabaseConfig(BaseSettings):host:str="localhost"port:int=5432max_connections:int=20classAppSettings(BaseSettings):app_name:str="MyApp"database:DatabaseConfig=Field(default_factory=DatabaseConfig)classConfig:env_prefix="APP_"

场景2:API响应模型

frompydanticimportBaseModel,FieldfromtypingimportList,OptionalfromdatetimeimportdatetimeclassApiResponse(BaseModel):success:bool=Truemessage:str="操作成功"data:Optional[dict]=Field(default_factory=dict)errors:List[str]=Field(default_factory=list)timestamp:datetime=Field(default_factory=datetime.now)

总结

default_factory是Pydantic中处理默认值的强大工具,特别适用于:

  1. 可变对象:列表、字典、集合等
  2. 嵌套模型:包含其他Pydantic模型的字段
  3. 动态值:需要在运行时计算的默认值
  4. 复杂对象:需要调用构造函数创建的对象

记住核心原则:

  • 不可变对象用default
  • 可变对象用default_factory
  • 需要动态创建的对象用default_factory

掌握了default_factory,你就能避免很多常见的陷阱,写出更安全、更可维护的代码!


相关阅读

  • Pydantic官方文档
  • Python可变与不可变对象详解

希望这篇文章对你有帮助!如果你有任何问题,欢迎在评论区讨论。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/19 18:23:44

企业微信SCRM对接API:加好友拉群发消息

做 SCRM,最后都要解决一件事:业务系统能不能驱动企业微信完成客户运营。 官方接口能覆盖一部分,但客服经常会遇到:客户群发不了实时消息、群机器人进不了外部群、加好友拉群发圈要员工反复点。 先说结论 大多数团队真正要用的不…

作者头像 李华
网站建设 2026/8/19 18:21:19

AI 生成代码的质量看护:测试、评审、验证闭环怎么建才靠谱

摘要引入 Coding Agent 之后,团队的代码产出量可能放大 5 到 10 倍,而评审人力不可能同步放大。质量看护的思路必须被迫转变:从"人工逐行 review"转向"自动化验证前置、人工只审关键"。本文基于多个团队的真实改造&#…

作者头像 李华
网站建设 2026/8/19 18:20:52

DouK-Downloader:抖音TikTok数据采集与批量下载完整指南

DouK-Downloader:抖音TikTok数据采集与批量下载完整指南 【免费下载链接】TikTokDownloader TikTok 发布/喜欢/合辑/直播/视频/图集/音乐;抖音发布/喜欢/收藏/收藏夹/视频/图集/实况/直播/音乐/合集/评论/账号/搜索/热榜数据采集工具/下载工具 项目地址…

作者头像 李华
网站建设 2026/8/19 18:20:21

用系统语言重写服务前的评审方法

用系统语言重写服务前的评审方法 评审先追不变量 Rust 重写服务的评审不该停在“能否编译”。先把 FFI 边界、异步取消与错误码映射写成可检查的约束:什么情况下允许、失败时由谁释放资源、调用方能依赖什么。随后沿真实调用链检查这些约束有没有被绕开。 逐项检查 …

作者头像 李华
网站建设 2026/8/19 18:20:21

ipatool 实战:三步把 App Store 里的任意应用下载成 IPA 文件

ipatool 实战:三步把 App Store 里的任意应用下载成 IPA 文件 【免费下载链接】ipatool Command-line tool that allows searching and downloading app packages (known as ipa files) from the iOS App Store 项目地址: https://gitcode.com/GitHub_Trending/ip…

作者头像 李华
网站建设 2026/8/19 18:20:15

论文精读:Hound如何用AI Agent在智能合约中猎杀安全漏洞?

论文精读:Hound如何用AI Agent在智能合约中猎杀安全漏洞? 【免费下载链接】hound Language-agnostic AI auditor that autonomously builds and refines adaptive knowledge graphs for deep, iterative code reasoning. 项目地址: https://gitcode.co…

作者头像 李华