登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  python教程

tomllib 怎样读取 TOML 配置

来源:17golang原创

时间:2026-10-25 13:41:03 196浏览 收藏

tomllib 读取 TOML 配置时只有两个核心入口:文件用 tomllib.load(),已经在内存中的文本用 tomllib.loads()。前者接收可读取的二进制文件对象,后者接收 str,两者都会返回一个 Python dict。项目使用 Python 3.11 及以后版本时,可以直接导入标准库模块。

官方文档:https://docs.python.org/3/library/tomllib.html

先把输入类型选对:打开 TOML 文件时使用 rb,不要把文本文件对象直接传给 load;如果配置已经是字符串,就用 loads。语法错误由 TOMLDecodeError 报告,字段缺失则属于解析后的业务校验。
要点速览
  • load 读取二进制文件对象,loads 读取字符串。
  • TOML 的表、数组、日期和数字会按规则转换到 Python 对象,结果仍需业务代码检查必填字段。
  • 先固定输入规模,再用同一测量方法比较读取基线;不要把未经执行的示例数字写成性能结论。

最小写法:文件和字符串分别用 load、loads

文件入口的关键不是函数名本身,而是文件模式。官方接口要求 load 的第一个参数是可读取的二进制文件对象,因此最小写法是 open("config.toml", "rb")。字符串入口则直接把 TOML 文本传给 loads。

import tomllib

# 文件入口必须保持二进制读取,返回值是普通字典。
with open("config.toml", "rb") as config_file:
    config = tomllib.load(config_file)

# 文本已经在内存中时,使用 loads;它接收 str 而不是 bytes。
inline_config = tomllib.loads('''
[server]
host = "127.0.0.1"
port = 8080
''')

# 先取表,再取字段;字段是否存在由业务代码决定。
server = config.get("server", {})
host = server.get("host", "127.0.0.1")
port = server.get("port", 8080)

如果配置文件内容与字符串示例相同,两种入口产生的结构都可以按 config["server"]["port"] 读取。示例中的默认值只表示应用层的兜底策略,不是 tomllib 自动补出的字段。

tomllib 的 load、loads 输入契约与 dict 配置结果关系说明图
图1:结构说明图,展示二进制文件、TOML 字符串、两个读取入口与 dict 配置之间的静态关系,不是运行截图。

类型转换决定了读取结果长什么样

tomllib 不把所有值都返回字符串。TOML 文档会被转换为字典;字符串、整数、浮点数和布尔值分别对应 str、int、float 和 bool;表与内联表对应 dict,数组对应 list。日期时间还可能得到 datetime、date 或 time。

# 这个文件展示读取后的 Python 类型边界。
name = "demo"
retries = 3
ratio = 0.75
enabled = true
release-date = 2026-10-25
regions = ["cn", "us"]

[database]
host = "localhost"
port = 5432
import tomllib
from decimal import Decimal

toml_text = '''
price = 12.50
[database]
port = 5432
'''

# parse_float 可以把浮点字面量交给 Decimal,避免业务金额直接使用 float。
config = tomllib.loads(toml_text, parse_float=Decimal)
price = config["price"]
db_port = config["database"]["port"]

# 这里的类型取决于 TOML 写法,不要只按配置字段名称猜测。
print(type(price).__name__, type(db_port).__name__)

parse_float 会接收每个 TOML 浮点数的文本;如果传入 Decimal,读取后的浮点值就会按该类型构造。这个回调不能返回 dict 或 list,否则会引发 ValueError。读取完成后,仍然应该把端口、重试次数等字段转换成应用真正接受的范围。

解析错误和字段缺失不要混在一起处理

文件存在并不代表 TOML 合法。引号没有闭合、表语法写错等问题会在解析阶段抛出 tomllib.TOMLDecodeError;语法合法但缺少 database.host,则属于解析成功后的业务问题。两者的处理动作不同,建议保留原始异常信息,同时对业务字段给出清晰提示。

import tomllib

def read_config(path):
    try:
        # 只捕获 TOML 语法错误,文件权限等 I/O 错误继续交给上层。
        with open(path, "rb") as config_file:
            return tomllib.load(config_file)
    except tomllib.TOMLDecodeError as exc:
        # 解析失败时保留官方异常,便于定位行列位置。
        raise ValueError(f"配置文件不是合法 TOML:{exc}") from exc

config = read_config("config.toml")
database = config.get("database")
if not isinstance(database, dict) or "host" not in database:
    # 这里是业务字段校验,不要伪装成 TOML 语法错误。
    raise ValueError("配置缺少 database.host")

如果要向用户展示错误位置,可以使用异常提供的消息;较新的 Python 文档还列出 msg、doc、pos、lineno 和 colno 属性。不要用字符串比较代替异常类型判断,也不要为了“容错”把所有 ValueError 都吞掉。

TOML 类型转换、TOMLDecodeError 与业务字段读取的边界说明图
图2:边界说明图,区分 TOML 类型转换、语法解析异常和解析后字段访问,不是运行证据。

用固定输入建立读取基线,再决定是否复用结果

如果同一个配置文件会被多个请求反复读取,先建立基线:固定文件大小、读取次数和 Python 版本,分别记录“每次打开并解析”和“启动时解析一次、后续复用字典”的耗时。下面的代码只提供测量方法,不填入未经执行的毫秒数。

import time
import tomllib

def load_once(path):
    # 每次调用都打开并解析,用来定义重复读取基线。
    with open(path, "rb") as config_file:
        return tomllib.load(config_file)

start = time.perf_counter()
for _ in range(100):
    load_once("config.toml")
elapsed = time.perf_counter() - start

# 记录次数、文件大小和 elapsed,而不是把一次机器结果推广给所有环境。
print({"reads": 100, "seconds": elapsed})

配置是进程级静态数据时,通常可以在启动阶段读取一次并复用结果;配置热更新则要明确重新加载时机、并发可见性和失败回退。tomllib 只提供读取,不提供写回 TOML 的 API;需要生成或编辑文件时,应另选写入工具,并重新定义格式保留要求。

读取 TOML 前后的速查清单

  • 文件使用 open(path, "rb"),内存字符串使用 tomllib.loads(text)。
  • 确认 Python 版本满足项目对 tomllib 的要求。
  • 按类型读取字段,别把日期、数组和表当成普通字符串。
  • 将 TOMLDecodeError 与必填字段缺失分开提示。
  • 反复访问的配置先测量,再选择启动时读取或按需读取。
  • 不把 tomllib 当作 TOML 写入器,也不把示例代码的输出当成实测结果。

常见问题

tomllib.load 为什么要用 rb 打开?

因为官方接口要求可读取的二进制文件对象。文本已经在内存中时,不要绕过文件模式去猜测,直接使用 tomllib.loads。

tomllib 能不能修改并保存 TOML?

不能。它是标准库中的 TOML 读取模块,不提供写入接口。读取后的字典可以在内存中修改,但要保存回 TOML,需要另选写入方案并考虑格式保留。

字段不存在应该捕获 TOMLDecodeError 吗?

不应该。语法错误由 TOMLDecodeError 表示;字段缺失发生在解析成功之后,应由业务校验处理。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>