Tomli 全面教程:常用 API 串联与实战指南

大家好,我是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

五、常见问题与注意事项

  1. 编码要求:TOML 文件必须使用 UTF-8 编码,否则可能解析失败;
  2. 文件打开模式tomli.load() 必须以 rb(二进制)模式打开文件,避免编码冲突;
  3. 类型映射 :Tomli 严格遵循 TOML → Python 类型映射(如 TOML 日期时间 → datetime.datetime);
  4. 注释处理:解析结果中不会包含注释信息,Tomli 会直接忽略;
  5. 版本兼容: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 数据的「解析 + 生成」全流程。

相关推荐
Asurplus2 小时前
【VUE】15、安装包管理工具yarn
前端·vue.js·npm·node.js·yarn
liangshanbo12152 小时前
Mac M3 安装 Antigravity Agent “已损坏“ 问题解决方案
前端·macos·antigravity
sszdlbw2 小时前
前后端在服务器的部署
运维·服务器·前端·后端
马卫斌 前端工程师2 小时前
vue 多个请求要同时拉取数据,写一个方法
前端·javascript·vue.js
苏打水com2 小时前
第十篇:Day28-30 工程化优化与部署——从“能跑”到“好用”(对标职场“项目上线”需求)
前端·css·vue·html·js
写代码的皮筏艇2 小时前
react hooks中的useState
前端·javascript
fruge2 小时前
React Fiber 架构详解:为什么它能解决页面卡顿问题?
前端·react.js·架构
lin62534222 小时前
Android仿小米视频播放器的缩放滚轮
android·git·github