配置文件读取:configparser 操作 INI 文件、JSON/YAML 配置文件解析
做批量对接参数调试的时候,最头疼的是什么?
我个人觉得,是参数改动后脚本里到处硬编码,改一处崩三处。
配置文件,说白了就是把这些参数抽出来,放到一个单独的文件里。脚本只管读,不改逻辑。
这一章我带你过三种最常见的格式:INI、JSON 和 YAML。每种我都会讲怎么读、怎么写,以及实战中容易踩的坑。
1. INI 文件:老牌简单,但别太信任它
INI 格式结构简单:节(section)、键(key)、值(value)。Python 自带 configparser 模块,不用装第三方包。
先看一个典型的 INI 文件:
[Database]
host = 192.168.1.100
port = 5432
user = admin
password = secret123
[Logging]
level = INFO
output = ./logs/app.log
max_size_mb = 50
读取的代码也很直接:
import configparser
config = configparser.ConfigParser()
config.read('config.ini')
db_host = config['Database']['host']
db_port = config.getint('Database', 'port') # 转成 int
log_level = config.get('Logging', 'level', fallback='DEBUG') # 带默认值
print(f"连接 {db_host}:{db_port}")
嗯,这里要注意几个地方。
如果你在 INI 文件里写
Host,然后代码里用 config['Database']['host'] 是能读到的;但反过来,如果文件里用小写,代码里用大写,就会报错。解决方案:读写统一用小写,或者用
ConfigParser(dict_type=collections.OrderedDict) 之类的高级选项。
getint()、getfloat()、getboolean(),避免手动转换时出类型错误。比如
port = config.getint('Database', 'port') 会比 int(config['Database']['port']) 安全得多。
INI 的缺点很明显:不支持嵌套、不支持数组、不支持多行文本。如果你的参数结构稍微复杂一点,就该考虑 JSON 或 YAML 了。
2. JSON 配置文件:简单可靠,但别忘记编码
JSON 是结构化数据的事实标准,Python 的 json 模块性能高、兼容性好。
一个典型的 JSON 配置文件:
{
"server": {
"host": "0.0.0.0",
"port": 8080,
"workers": 4
},
"database": {
"host": "192.168.1.100",
"port": 5432,
"pool_size": 10
},
"log_level": "INFO"
}
读取方法:
import json
with open('config.json', 'r', encoding='utf-8') as f:
config = json.load(f)
host = config['server']['host']
port = config['server']['port']
写配置文件也简单:
with open('config.json', 'w', encoding='utf-8') as f:
json.dump(config, f, ensure_ascii=False, indent=2)
- 读写一定用
encoding='utf-8',否则中文会乱码。 ensure_ascii=False让中文显示为中文,否则会被转成 \uXXXX。indent=2让 JSON 文件有换行缩进,方便人眼阅读。
我在项目中遇到过一个奇怪问题:同一个 JSON 文件,在 Linux 下跑正常,在 Windows 下就报编码错误。检查后发现 Windows 系统默认编码是 GBK,打开文件时没指定 utf-8 导致。从此我写代码一律显式声明 encoding。
3. YAML 配置文件:优雅但小心「序列化炸弹」
YAML 是目前 DevOps、Kubernetes 等领域最流行的配置格式,支持锚点、引用、嵌套,可读性极强。
Python 里处理 YAML 需要安装 PyYAML:
pip install pyyaml
YAML 文件示例:
server:
host: 0.0.0.0
port: 8080
workers: 4
database:
host: 192.168.1.100
port: 5432
pool_size: 10
log_level: INFO
读取代码:
import yaml
with open('config.yaml', 'r', encoding='utf-8') as f:
config = yaml.safe_load(f)
host = config['server']['host']
port = config['server']['port']
yaml.load(),除非你知道自己在做什么。yaml.load() 默认会构造任意 Python 对象,攻击者可以构造恶意 YAML 远程执行代码。安全做法永远是
yaml.safe_load(),它能解析标准 YAML 标签,不会执行任意代码。我曾经接手过一个遗留项目,里面用的
yaml.load,结果被安全扫描扫出来高危漏洞。全组花了三天把每个 YAML 文件审计了一遍,才改成 safe_load。
--- 分隔了多个文档,用 yaml.safe_load_all() 迭代读取所有文档。
4. 三种配置文件的核心对比
| 特性 | INI | JSON | YAML |
|---|---|---|---|
| 标准库支持 | configparser | json | 需安装 PyYAML |
| 嵌套支持 | 不支持 | 良好 | 优秀(锚点/别名) |
| 注释 | 支持 | 不支持 | 支持 |
| 多行文本 | 困难 | 需转义 | 原生支持 |
| 安全风险 | 低 | 低 | 使用 safe_load |
| 学习成本 | 极低 | 低 | 中等 |
选哪种?我个人的原则是:
- 项目只有几个简单参数 → INI 就够,零依赖。
- 需要做 API 交互、数据交换 → JSON,因为它是 JS 原生格式,跨语言通用。
- 项目配置复杂、团队多人协作、需要注释 → YAML,可读性最好。
5. 踩坑与最佳实践
实战中我经常看到同学犯的错,列出来给你参考:
- 配置文件路径写死。 应该用
os.path.join(os.path.dirname(__file__), 'config.yaml')或环境变量 + 默认值。 - 读配置时不处理异常。 文件不存在、格式错误、键缺失,最好都 try/except 并给出明确报错。
- 把密码/密钥明文写在配置文件里。 建议用环境变量或专用的 secrets 管理工具,比如
python-dotenv。 - JSON key 重复。 标准 JSON 不允许多个同名 key,但某些解析器会覆盖。如果你用它做配置,确保唯一。
- YAML 缩进混用 Tab 和空格。 YAML 严格依赖缩进,建议统一用 2 个空格。
import json
import yaml
import configparser
from pathlib import Path
def load_config(path):
ext = Path(path).suffix.lower()
with open(path, 'r', encoding='utf-8') as f:
if ext == '.json':
return json.load(f)
elif ext in ('.yaml', '.yml'):
return yaml.safe_load(f)
elif ext == '.ini':
cfg = configparser.ConfigParser()
cfg.read_file(f)
return {s: dict(cfg.items(s)) for s in cfg.sections()}
else:
raise ValueError(f"不支持的配置格式: {ext}")
看到这张图应该就清楚了。无论你读哪种格式的文件,最终都会得到一个 Python dict。这样一来,脚本内部的业务逻辑就可以统一用 config['某层']['某键'] 访问,不用管原始文件是 INI 还是 YAML。