大家好,我是jobleap.cn的小九。 Tomli 是 Python 生态中轻量、合规的 TOML 解析库,完全遵循 TOML 1.0.0 规范,仅专注于 TOML 数据的解析(写入需搭配 tomli-w),支持 Python 3.7+,纯 Python 实现且无第三方依赖。本教程将全面讲解 Tomli 的核心 API,通过实战案例串联所有常用用法,帮助你熟练掌握 TOML 解析技巧。
一、环境准备:安装 Tomli
首先通过 pip 安装 Tomli 库,命令如下:
bash
pip install tomli
验证安装是否成功:
python
import tomli
print(tomli.__version__) # 输出示例:2.0.1
二、核心 API 总览
Tomli 的核心 API 极其简洁,核心包含 2 个解析函数 + 1 个异常类:
| API 名称 | 作用 |
|---|---|
tomli.load(fp, **kwargs) |
从文件对象(file-like object)解析 TOML 数据,返回 Python 字典 |
tomli.loads(s, **kwargs) |
从字符串解析 TOML 数据,返回 Python 字典 |
tomli.TomliDecodeError |
解析过程中出现 TOML 语法错误时抛出的异常类 |
可选参数(kwargs)说明
parse_float:自定义浮点数解析函数(默认float)parse_int:自定义整数解析函数(默认int)parse_bool:自定义布尔值解析函数(默认bool)parse_datetime:自定义日期时间解析函数(默认datetime.datetime)
三、常用 API 实战详解
3.1 tomli.loads():解析 TOML 字符串
适用于从内存中的字符串解析 TOML 数据,是最基础的核心用法。
示例 1:解析基础数据类型(字符串/数字/布尔/日期时间)
Tomli 会自动将 TOML 类型映射为对应的 Python 类型,注释会被直接忽略:
python
import tomli
# 定义包含基础类型的 TOML 字符串
toml_str = """
# 这是注释(Tomli 会忽略)
title = "Tomli Tutorial"
version = 2.0.1
is_active = true
release_date = 2025-12-10T10:00:00Z # TOML 标准日期时间格式
"""
# 解析字符串
data = tomli.loads(toml_str)
# 访问解析后的数据
print("标题:", data["title"]) # 输出:Tomli Tutorial
print("版本:", data["version"]) # 输出:2.0.1
print("是否激活:", data["is_active"]) # 输出:True
print("发布时间:", data["release_date"]) # 输出:2025-12-10 10:00:00+00:00
print("时间类型:", type(data["release_date"])) # 输出:<class 'datetime.datetime'>
示例 2:解析数组(列表)与嵌套数组
python
import tomli
toml_str = """
# 简单字符串数组
fruits = ["apple", "banana", "orange"]
# 混合数字数组
numbers = [1, 2, 3, 4.5]
# 嵌套数组(二维矩阵)
matrix = [[1, 2], [3, 4]]
"""
data = tomli.loads(toml_str)
print("水果列表:", data["fruits"]) # 输出:['apple', 'banana', 'orange']
print("数字数组:", data["numbers"]) # 输出:[1, 2, 3, 4.5]
print("嵌套数组:", data["matrix"]) # 输出:[[1, 2], [3, 4]]
示例 3:解析表(字典)与嵌套表
TOML 的「表」对应 Python 字典,支持多层嵌套和内联写法:
python
import tomli
toml_str = """
# 基础表
[database]
host = "127.0.0.1"
port = 3306
user = "root"
# 嵌套表
[database.connection]
timeout = 30
charset = "utf8mb4"
# 内联表(简洁写法)
server = { ip = "192.168.1.1", port = 8080 }
"""
data = tomli.loads(toml_str)
print("数据库主机:", data["database"]["host"]) # 输出:127.0.0.1
print("连接超时:", data["database"]["connection"]["timeout"]) # 输出:30
print("服务器端口:", data["server"]["port"]) # 输出:8080
示例 4:解析数组表(表的数组)
适用于多个同结构的表(如列表式配置):
python
import tomli
toml_str = """
# 数组表(多个用户配置)
[[users]]
name = "Alice"
age = 25
[[users]]
name = "Bob"
age = 30
[[users]]
name = "Charlie"
age = 35
"""
data = tomli.loads(toml_str)
# 遍历用户列表
for user in data["users"]:
print(f"姓名:{user['name']},年龄:{user['age']}")
# 输出:
# 姓名:Alice,年龄:25
# 姓名:Bob,年龄:30
# 姓名:Charlie,年龄:35
3.2 tomli.load():解析 TOML 文件
当 TOML 数据存储在文件中时,使用 load() 更高效(直接读取文件对象解析)。
步骤 1:创建 TOML 配置文件(config.toml)
toml
# 应用配置文件
[app]
name = "MyApp"
debug = false
[app.log]
level = "INFO"
path = "./logs/app.log"
[database]
host = "localhost"
port = 5432
dbname = "mydb"
user = "postgres"
步骤 2:使用 load() 解析文件
⚠️ 注意:必须以二进制模式(rb) 打开文件(避免编码问题):
python
import tomli
# 推荐使用 with 语句(自动关闭文件)
with open("config.toml", "rb") as f:
config = tomli.load(f)
# 访问配置项
print("应用名称:", config["app"]["name"]) # 输出:MyApp
print("日志级别:", config["app"]["log"]["level"]) # 输出:INFO
print("数据库名称:", config["database"]["dbname"]) # 输出:mydb
3.3 自定义解析函数(可选参数)
通过 parse_* 参数自定义解析逻辑,适用于特殊场景(如格式化数字、日期):
python
import tomli
# 自定义浮点数解析:保留 2 位小数
def custom_parse_float(s):
return round(float(s), 2)
toml_str = """
pi = 3.1415926
price = 99.999
"""
# 传入自定义解析函数
data = tomli.loads(toml_str, parse_float=custom_parse_float)
print("圆周率:", data["pi"]) # 输出:3.14
print("价格:", data["price"]) # 输出:100.0
3.4 异常处理(TomliDecodeError)
当 TOML 语法错误时,会抛出 TomliDecodeError,需捕获并处理:
python
import tomli
from tomli import TomliDecodeError
# 错误的 TOML 字符串(缺少等号)
invalid_toml = """
title "Tomli Tutorial" # 语法错误:key 后缺少 =
"""
try:
data = tomli.loads(invalid_toml)
except TomliDecodeError as e:
print(f"解析失败:{e}")
print(f"错误位置:行 {e.lineno},列 {e.colno}")
# 输出示例:
# 解析失败:Invalid statement at line 2, column 7: expected '=' after key
# 错误位置:行 2,列 7
四、综合实战:解析配置文件并应用
下面通过完整案例串联所有 API,实现「加载配置 → 验证配置 → 应用配置」的全流程。
4.1 编写配置文件(app_config.toml)
toml
# 核心配置
[core]
app_name = "DataProcessor"
version = "1.0.0"
enable_cache = true
cache_ttl = 3600
# 数据源配置(数组表)
[[datasources]]
name = "mysql"
type = "relational"
config = { host = "127.0.0.1", port = 3306, db = "source_db", user = "root" }
[[datasources]]
name = "redis"
type = "nosql"
config = { host = "127.0.0.1", port = 6379, db = 0 }
# 输出配置
[output]
format = "json"
path = "./output"
compression = { enable = true, level = 6 }
4.2 编写解析与应用代码
python
import tomli
from tomli import TomliDecodeError
import os
class ConfigLoader:
"""配置加载器,封装 Tomli 解析逻辑"""
def __init__(self, config_path):
self.config_path = config_path
self.config = None
def load_config(self):
"""加载并解析 TOML 配置文件"""
try:
# 检查文件是否存在
if not os.path.exists(self.config_path):
raise FileNotFoundError(f"配置文件 {self.config_path} 不存在")
# 解析 TOML 文件
with open(self.config_path, "rb") as f:
self.config = tomli.load(f)
# 验证核心配置
self._validate_core_config()
print("配置加载并验证成功!")
return self.config
except FileNotFoundError as e:
print(f"错误:{e}")
return None
except TomliDecodeError as e:
print(f"配置语法错误:行 {e.lineno},列 {e.colno} → {e}")
return None
except Exception as e:
print(f"未知错误:{e}")
return None
def _validate_core_config(self):
"""验证核心配置项是否存在"""
required_keys = ["app_name", "enable_cache"]
for key in required_keys:
if key not in self.config.get("core", {}):
raise ValueError(f"核心配置缺失:{key}")
def get_datasource(self, name):
"""根据名称获取数据源配置"""
if not self.config:
return None
for ds in self.config.get("datasources", []):
if ds["name"] == name:
return ds
return None
# 实例化并加载配置
config_loader = ConfigLoader("app_config.toml")
config = config_loader.load_config()
if config:
# 1. 打印核心配置
print("\n=== 核心配置 ===")
print(f"应用名称:{config['core']['app_name']}")
print(f"是否启用缓存:{config['core']['enable_cache']}")
# 2. 获取 MySQL 数据源配置
print("\n=== MySQL 数据源 ===")
mysql_ds = config_loader.get_datasource("mysql")
if mysql_ds:
print(f"类型:{mysql_ds['type']}")
print(f"主机:{mysql_ds['config']['host']}")
# 3. 输出配置
print("\n=== 输出配置 ===")
print(f"格式:{config['output']['format']}")
print(f"压缩级别:{config['output']['compression']['level']}")
运行结果
ini
配置加载并验证成功!
=== 核心配置 ===
应用名称:DataProcessor
是否启用缓存:True
=== MySQL 数据源 ===
类型:relational
主机:127.0.0.1
=== 输出配置 ===
格式:json
压缩级别:6
五、常见问题与注意事项
- 编码要求:TOML 文件必须使用 UTF-8 编码,否则可能解析失败;
- 文件打开模式 :
tomli.load()必须以rb(二进制)模式打开文件,避免编码冲突; - 类型映射 :Tomli 严格遵循 TOML → Python 类型映射(如 TOML 日期时间 →
datetime.datetime); - 注释处理:解析结果中不会包含注释信息,Tomli 会直接忽略;
- 版本兼容:Tomli 2.x 仅支持 TOML 1.0.0,若需兼容旧版 TOML(0.5.x),请使用 Tomli 1.x。
六、扩展:TOML 写入(tomli-w)
Tomli 仅负责解析,若需生成 TOML 文件,可使用配套的 tomli-w 库:
bash
pip install tomli-w
示例:生成 TOML 文件
python
import tomli_w
# 定义 Python 字典
data = {
"title": "Tomli-W Demo",
"database": {"host": "localhost", "port": 3306}
}
# 写入 TOML 文件
with open("output.toml", "wb") as f:
tomli_w.dump(data, f)
总结
Tomli 的核心 API 仅有 load()(解析文件)和 loads()(解析字符串),简洁易上手。通过本教程的实战案例,你已掌握基础类型解析、复杂结构解析、异常处理、自定义解析函数等所有常用用法。在实际项目中,Tomli 是处理 TOML 配置文件的首选库,配合 tomli-w 可完成 TOML 数据的「解析 + 生成」全流程。