configparser 缺失字段需用 fallback 参数(python 3.4+)或 try/except,且 fallback 不作用于 section 缺失;pydantic-settings 提供类型校验、环境变量优先覆盖及多源配置能力,替代 configparser 更健壮。

configparser 读取配置时字段缺失导致 KeyError
Python 标准库 configparser 默认不提供“缺失字段返回默认值”的能力,直接用 config.get('section', 'key') 遇到 key 不存在就会抛 NoSectionError 或 NoOptionError,不是 KeyError,但效果类似——程序中断。很多人误以为它像字典一样支持 .get(key, default),其实不支持。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 必须用
config.get('section', 'key', fallback='default')——fallback参数是 Python 3.4+ 才有的,低于该版本需手动 try/except - 如果 section 本身可能不存在,得先用
config.has_section('section')判断,再调用get;否则fallback对 section 缺失无效 - 注意
fallback只对 option 缺失生效,section 缺失仍会报错,这点容易被忽略 - 类型转换(如
getint)不支持fallback,必须自己兜底:int(config.get('db', 'port', fallback='5432'))
pydantic-settings 替代 configparser 的真实收益
用 pydantic-settings(v2+)不是为了“更酷”,而是解决 configparser 在类型校验、环境变量覆盖、嵌套结构上的硬伤。比如你写了个 timeout = 30,configparser 返回字符串,你得自己转 int;而 pydantic 能在加载时就报错或自动转。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 定义模型时用
Field(default=...)设默认值,用Field(default_factory=dict)防止可变默认参数陷阱 - 环境变量优先级默认高于配置文件,想反转?传
_env_parse=True并调整SettingsConfigDict(env_file='.env', env_file_encoding='utf-8') - 多个配置源叠加(如 YAML + 环境变量 + 命令行参数),用
PydanticBaseSettingsSource自定义,但别一上来就搞复杂,先跑通单源 - 注意
pydantic-settings不兼容老版pydantic,装错版本会 import 失败,报 <code>ModuleNotFoundError: No module named 'pydantic_settings'
JSON/YAML 配置文件中布尔值和 None 的坑
用 json.load() 或 yaml.safe_load() 读配置时,true/false 是合法布尔字面量,但 True/False(首字母大写)在 YAML 里是布尔,在 JSON 里直接解析失败;null 是 YAML 合法空值,JSON 里得写 null,但 Python 里对应的是 None —— 这些差异会导致“配置明明写了,程序却当没写”。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 统一用小写:YAML 中写
debug: false,不写Debug: False;JSON 中只用"debug": false - 避免在配置里直接写
None,改用字符串占位(如"api_key": "")或显式标记("api_key": null),然后在代码里做if config.api_key is None: - 用
pydantic模型字段加default=None或default_factory=lambda: None,比靠配置文件表达 “无值” 更可靠 - YAML 的
!!null强制类型标注极少必要,反而增加维护成本,除非你真需要区分null和空字符串
环境隔离时配置覆盖顺序的实际控制
开发、测试、生产共用一套配置结构,但值不同。很多人靠“加载多个文件 + 字典 update”实现覆盖,结果发现 dev.ini 覆盖了 prod.ini 里的某个字段,上线就出事——因为覆盖逻辑没对齐预期。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
configparser.read([prod.ini, dev.ini])是按列表顺序读取,后加载的覆盖前加载的,但仅限同 section 同 key;不同 section 不会合并,只会新增 - pydantic-settings 的
settings = Settings(_env_file='.env.dev')会把.env.dev里定义的变量注入环境,再加载.env就会被覆盖,顺序由你传参决定 - 别依赖文件名隐含优先级(如
base.conf和override.conf),显式声明加载顺序,或用os.getenv('ENV', 'prod')动态拼路径 - 最稳的方式是:所有环境共享一个基础配置模型,各环境只提供 delta 文件,用
deep_update(base_dict, delta_dict)合并(注意 list 类型不会自动 append,而是替换)










