
咱做 Python 项目时,总需要配置文件吧?比如数据库地址、日志级别、接口密钥这些 —— 总不能写死在代码里,改个配置还要改代码多麻烦!之前可能用过 JSON、YAML,但今天要讲的TOML,绝对是 Python 开发者的 “配置神器”,简单好懂还跟 Python 很搭,3 分钟就能上手!
TOML 全称是 “Tom's Obvious Minimal Language”(汤姆的直观极简语言),2013 年就诞生了,核心就是两个字:好读、好写。
咱先跟常见的配置格式比一比,就知道它为啥香了:
配置格式 | 优点 | 缺点 | 对 Python 友好度 |
|---|---|---|---|
JSON | 通用、易解析 | 不支持注释、写起来麻烦 | 一般(要手动处理注释问题) |
YAML | 支持注释、简洁 | 语法严格(空格错了就崩)、不安全 | 还行(但容易踩坑) |
TOML | 支持注释、语法简单、类型明确 | 无明显缺点 | 极高(注释跟 Python 一模一样!) |
TOML 支持的常见数据类型,跟 Python 几乎对应,不用额外转换脑子:
true/false,全小写)datetime对象)这部分是核心,咱一步一步来,每个知识点都配例子,看完就能写!
TOML 文件的后缀是 .toml,比如项目里叫 config.toml,直接用记事本、VS Code 都能编辑,不用装任何工具。
就跟 Python 的字典键值对一样,左边是 “键”(配置名),右边是 “值”(配置内容),中间用 = 连接。
先看个简单的例子,把下面内容写到 config.toml 里:
# 这是注释!跟Python的#注释一模一样,太亲切了~
# 字符串(单双引号都行,特殊字符用双引号转义)
project_name = "我的Python项目" # 双引号
author = '张三' # 单引号
desc = "他说:"TOML真简单!"" # 双引号里转义双引号
# 数字(整数、浮点数、负数都能直接写)
port = 8080 # 整数
timeout = 3.5 # 浮点数
discount = -0.2 # 负数
# 布尔值(全小写!true是真,false是假,别写True/False)
debug_mode = true # 调试模式开
is_production = false# 不是生产环境这里要注意两个小细节:
#,从#开始到行尾都是注释,不能写在字符串里(除非转义)True 会被当成字符串,直接报错!如果配置多了,比如又有数据库配置、又有日志配置,堆在一起会很乱 —— 这时候就用 “表格” 来分组,表格用 [表格名] 表示,下面的键值对都属于这个表格。
比如给上面的 config.toml 加数据库和日志配置:
# 前面的配置不变,新增下面的表格
# 数据库配置表格(表格名:db)
[db]
host = "localhost" # 数据库地址
port = 3306 # 数据库端口
user = "root" # 用户名
password = "123456" # 密码
db_name = "my_db" # 数据库名
# 日志配置表格(表格名:log)
[log]
level = "INFO" # 日志级别:INFO/WARN/ERROR
file_path = "./logs/app.log" # 日志文件路径
max_size = 1024 # 日志文件最大大小(MB)这时候,这个 TOML 文件对应 Python 的结构就是个嵌套字典:
{
"project_name": "我的Python项目",
"db": {
"host": "localhost",
"port": 3306,
...
},
"log": {
"level": "INFO",
...
}
}如果表格还想再细分,比如数据库有 “主库” 和 “从库”,就用 [父表格.子表格] 写子表格。
继续加配置到 config.toml:
# 数据库主库(父表格db,子表格master)
[db.master]
host = "192.168.1.100"
port = 3306
# 数据库从库(父表格db,子表格slave)
[db.slave]
host = "192.168.1.101"
port = 3306对应 Python 的结构就是:
{
"db": {
"master": {"host": "192.168.1.100", ...},
"slave": {"host": "192.168.1.101", ...},
...
}
}如果表格里的配置很少,不想单独占几行,就用 {键1=值1, 键2=值2} 写 “内联表格”,相当于紧凑版的表格。
比如给项目加个 “作者信息” 的小表格,用内联写法:
# 内联表格:作者信息(一行搞定)
author_info = {name = "张三", email = "zhangsan@example.com", age = 28}这跟下面的普通表格写法完全一样,只是更紧凑:
[author_info]
name = "张三"
email = "zhangsan@example.com"
age = 28如果一个配置需要多个值(比如项目依赖的包、允许的 IP 列表),就用 [值1, 值2, 值3] 写数组,元素之间用逗号分隔,支持换行。
继续加配置到 config.toml:
# 数组:项目依赖的Python包(一行写)
dependencies = ["requests", "pandas", "numpy"]
# 数组:允许访问的IP列表(换行写,更清晰)
allowed_ips = [
"127.0.0.1",
"192.168.1.0/24",
"10.0.0.0/8"
]
# 多维数组(相当于Python的嵌套列表)
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]注意:数组里的元素类型可以不一样(比如 [1, "2", true]),但实际开发中建议统一类型,避免后续处理出错。
之前用 JSON 要json模块,用 YAML 要装pyyaml,但 Python 3.11 开始,内置了 tomllib模块 ,不用装任何第三方库,直接就能读 TOML 文件!
确保你的 Python 版本是 3.11+(检查方法:命令行输python --version,看到Python 3.11.x就行)。
如果是 3.10 及以下版本,也能玩:装个第三方库tomli(命令行输pip install tomli),用法跟tomllib几乎一样,只是导入时写import tomli as tomllib。
假设我们已经有了前面写好的 config.toml,现在写个read_config.py脚本,加载配置并打印出来:
# 导入内置的tomllib模块(3.11+)
import tomllib
# 1. 打开TOML文件并读取(注意用rb模式,因为tomllib需要二进制读取)
with open("config.toml", "rb") as f:
# 2. 解析TOML内容,转成Python字典
config = tomllib.load(f)
# 3. 打印整个配置字典,看看结构
print("=== 整个配置字典 ===")
print(config)
print("n")
# 4. 读取单个配置(跟字典取值一样)
print("=== 单个配置取值 ===")
print(f"项目名:{config['project_name']}")
print(f"调试模式:{config['debug_mode']}")
print("n")
# 5. 读取表格里的配置(嵌套字典取值)
print("=== 表格配置取值 ===")
print(f"数据库地址:{config['db']['host']}")
print(f"主库地址:{config['db']['master']['host']}")
print(f"日志级别:{config['log']['level']}")
print("n")
# 6. 读取数组配置(列表操作)
print("=== 数组配置取值 ===")
print(f"依赖包列表:{config['dependencies']}")
print(f"第一个依赖包:{config['dependencies'][0]}")
print(f"允许的IP数量:{len(config['allowed_ips'])}")把config.toml和read_config.py放在同一个文件夹里,然后命令行运行:
python read_config.py会输出这样的结果(格式可能略有不同,但内容一致):
=== 整个配置字典 ===
{'project_name': '我的Python项目', 'author': '张三', 'desc': '他说:"TOML真简单!"', 'port': 8080, 'timeout': 3.5, 'discount': -0.2, 'debug_mode': True, 'is_production': False, 'db': {'host': 'localhost', 'port': 3306, 'user': 'root', 'password': '123456', 'db_name': 'my_db', 'master': {'host': '192.168.1.100', 'port': 3306}, 'slave': {'host': '192.168.1.101', 'port': 3306}}, 'log': {'level': 'INFO', 'file_path': './logs/app.log', 'max_size': 1024}, 'author_info': {'name': '张三', 'email': 'zhangsan@example.com', 'age': 28}, 'dependencies': ['requests', 'pandas', 'numpy'], 'allowed_ips': ['127.0.0.1', '192.168.1.0/24', '10.0.0.0/8'], 'matrix': [[1, 2, 3], [4, 5, 6], [7, 8, 9]]}
=== 单个配置取值 ===
项目名:我的Python项目
调试模式:True
=== 表格配置取值 ===
数据库地址:localhost
主库地址:192.168.1.100
日志级别:INFO
=== 数组配置取值 ===
依赖包列表:['requests', 'pandas', 'numpy']
第一个依赖包:requests
允许的IP数量:3完美!配置全读出来了,而且类型都是对的(debug_mode是布尔值,port是整数),不用手动转换类型~
TOML 支持 3 种时间格式,Python 读取后会自动转成datetime.datetime或datetime.date对象,不用自己解析字符串,太方便了!
在config.toml里加时间配置:
# 时间戳配置
[time_info]
release_date = 2024-05-20 # 仅日期(Python读成date对象)
start_time = 2024-05-20T14:30:00 # 日期+时间(本地时间,datetime对象)
deadline = 2024-05-20T14:30:00Z # 带UTC时区(datetime对象,utc=True)然后在 Python 代码里读取:
# 继续用上面的config变量
print("=== 时间戳处理 ===")
release_date = config['time_info']['release_date']
start_time = config['time_info']['start_time']
deadline = config['time_info']['deadline']
print(f"发布日期:{release_date},类型:{type(release_date)}") # 类型是datetime.date
print(f"开始时间:{start_time},类型:{type(start_time)}") # 类型是datetime.datetime
print(f"截止时间(UTC):{deadline}")运行后能看到时间类型是正确的,直接用datetime的方法处理(比如计算差值)就行。
TOML 语法简单,但遇到特殊情况要注意规范,不然会解析失败:
特殊场景 | 正确写法 | 错误写法 | 说明 |
|---|---|---|---|
键名含空格 |
|
| 键名有空格必须用双引号包起来 |
字符串含# |
|
| 字符串里的 #会被当成注释,必须用双引号包起来 |
键名是关键字 |
|
| 键名是 Python 关键字(if/for/while),必须用双引号 |
多行字符串 |
|
| 多行字符串用三个双引号,换行用 n 或直接换行 |
举个正确的例子,加到config.toml里:
# 键名含空格
"project version" = "1.0.0"
# 字符串含#
note = "这个配置#很重要"
# 多行字符串(直接换行也可以)
long_text = """这是一段
多行的字符串
不用写n也能换行"""Python 读取后能正确解析这些特殊配置,不会出错。
咱刚开始用 TOML,很容易踩这些坑,提前知道怎么解决能省很多时间!
错误提示:ModuleNotFoundError: No module named 'tomllib'
原因:tomllib 是 3.11 + 内置的,低版本没有。
解决办法:装第三方库tomli,用法完全一样:
pip install tomli然后 Python 代码里改导入:
import tomli as tomllib # 跟tomllib用法一样错误提示:KeyError: 'db_host'
原因:要么 TOML 里没有这个键,要么键名写错了(比如 TOML 里是db.host,代码里写成db_host)。
解决办法:
config字典,看实际的键名是什么(比如print(config))DB和db是两个不同的键)config['db']['host'],不是config['db.host'])错误提示:判断if config['debug_mode']时,不管写 True 还是 False 都为真。
原因:TOML 的布尔值必须全小写(true/false),写True会被当成字符串,字符串非空就是 True。
解决办法:把布尔值改成全小写:
debug_mode = true # 正确
# debug_mode = True # 错误,会被当成字符串问题描述:比如config['db']['master']['replica']['host'],写这么长容易错。
解决办法:用 Python 的解构赋值简化:
# 从config里把db.master.replica解构出来
db_master_replica = config['db']['master']['replica']
print(db_master_replica['host']) # 直接取值,不用写嵌套错误提示:UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 10: illegal multibyte sequence
原因:Windows 系统默认用 GBK 编码打开文件,而 TOML 文件是 UTF-8 编码。
解决办法:打开文件时指定编码为 UTF-8:
with open("config.toml", "rb", encoding="utf-8") as f: # 加encoding="utf-8"
config = tomllib.load(f)如果面试 Python 开发,可能会被问到 TOML 相关问题,提前准备好回答,加分!
回答思路:对比三者的优缺点,突出 TOML 对 Python 开发者的友好性。
参考回答:
“我选 TOML 主要因为三个点:
回答思路:分版本说明(3.11 + 内置 vs 低版本第三方),再讲注意事项。
参考回答:
“Python 加载 TOML 分两种情况:
import tomllib,然后用tomllib.load(文件对象)解析,注意打开文件要用 rb 模式(二进制读取)。pip install tomli),导入时用import tomli as tomllib,用法跟内置的完全一样。注意事项有三个:
回答思路:列举 TOML 的主要数据类型,对应 Python 类型,举简单例子。
参考回答:
“TOML 支持 6 种常用数据类型,对应 Python 的类型很明确:
比如 TOML 里写[db] host = "localhost",Python 读出来就是{"db": {"host": "localhost"}},完全是 Python 原生类型,不用额外处理。”
回答思路:从语法、键名、数据类型、文件编码四个方面排查。
参考回答:
“遇到解析错误,我会按这四步排查:
TomlDecodeError: Invalid key,说明键名有问题,检查键名是不是含空格没加引号;=,表格是不是用[ ]包裹,数组是不是用[ ];123a);如果还是找不到问题,就把 TOML 文件简化成最小版本(比如只留一个键值对),一步步加配置,找到出错的地方。”
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。