toml:迄今最适合 Python 项目的配置语言
一些语言用于编写和运行程序,比如我们熟知的 Python Java 等等;还有些语言只用来传递信息,例如 JSON、YAML,和这次要介绍的 toml。
Toml 是目前最适合 Python 项目的配置语言。
Toml 的语法
Toml 适合 Python主要体现在两点,一是语法非常相似,二是类型完美对应,随着后面的例子你会理解这两点。
首先,创建一个新的 toml 文件。
如果你和我一样使用 vscode,vscode 没有内置对 toml 的颜色高亮,我们需要通过插件实现。我使用的插件是 Even Better Toml。
注释
toml 的注释和 Python 一样,在行首使用 #
就可以了。
1
## This is a toml file.
键值对
创建键值对只需要等号就可定义,而且可以使用许多 Python 中的类型,先写一下比较熟悉的整数、字符串列表。
1
2
3
4
5
name = 'Hucci'
age = 59
sex = "Female"
hobbies = ['coding', 'reading', 'traveling']
birthdate = 1960-01-01T00:00:00Z
你可以看到我同时使用了单引号和双引号,这在 toml 中是合法的。不像 json 只认双引号。不过即使都合法,也会有细微的区别,如果要使用转义字符,就只能在双引号里面使用,不能在单引号里面使用。虽然转义字符不常用,但我们还是知道一下吧。
1
sex = "\"Female\""
除了这些常见类型,经常被解析为字符串的日期时间都也被正确解析。
这样我们就写好了一个简单的 toml 文件。
读取 toml
tomllib是 Python 3.11 中引入的标准库模块,用于解析 TOML 文件。如果你使用的是 Python 3.11 或更高版本,则不需要安装 tomllib,因为它已经包含在标准库中。
如果你使用的是 Python 3.10 或更低版本,就需要 pip install toml
。
1
2
3
4
5
## read_toml.py
import tomllib
with open('config.tml', 'br') as f:
config = tomllib.load(f)
这里需要说明打开方式是以二进制仅读取的方式打开。
为了更方便地查看结果,我需要 from pprint import pp
。
这样就将我们刚刚的 toml 读取为了一个字典。
1
2
3
4
5
{'name': 'Hucci',
'birthdate': datetime.datetime(1960, 1, 1, 0, 0, tzinfo=datetime.timezone.utc),
'age': 59,
'sex': 'Female',
'hobbies': ['coding', 'swimming']}
所有的类型都正确解析了,包括日期时间也正确解析为 datetime 类型。
Inline_table
Toml 的类型和 Python 的类型几乎是一一对应,字符串对应字符串,整数对应整数,列表对应列表,时间对应时间。就连 Toml 中唯一一个听起来有点陌生的类型 table,也对应了 Python 的字典。
创建一个 table 很容易,就像字典一样用花括号,非常符合 Python 思维。比如我的 shape 是身高一米体重 50。
1
shape = {height = 1, weight = 50}
解析出来就是 shape 所对应的 value 是一个字典。
1
2
3
4
5
6
{'name': 'Hucci',
'birthdate': datetime.datetime(1960, 1, 1, 0, 0, tzinfo=datetime.timezone.utc),
'age': 59,
'sex': 'Female',
'hobbies': ['coding', 'swimming'],
'shape': {'height': 1, 'weight': 50}}
创建表
但大部分情况下,我们的配置是层层叠叠的嵌套表,如果用花括号这种写法就太复杂难看了。
所以会使用另一种写法,toml 中创建表的写法,用方括号括起 table 的名称。比如说我要写我的各个账号的 username。
1
2
3
[account]
bilibili = 'hucciB'
youtube = 'hucciY'
这样解析的结果 social 所对应的 value 是一个字典,字典的 key 分别是 bilibili 和 youtube。
1
2
3
4
5
6
7
{'name': 'Hucci',
'birthdate': datetime.datetime(1960, 1, 1, 0, 0, tzinfo=datetime.timezone.utc),
'age': 59,
'sex': 'Female',
'hobbies': ['coding', 'swimming'],
'shape': {'height': 1, 'weight': 50},
'account': {'bilibili': 'hucciB', 'youtube': 'hucciY'}}
在表中再嵌套表
如果说我想再在这个表里面嵌套,比如说 bilibili 这个 key 所对应的又是一张表,表里面有 username 和 password 两个 key。就要这样写
1
2
3
4
[account]
bilibili.username = 'hucciB'
bilibili.password = 'hucciBPW'
youtube = 'hucciY'
这个 .
的写法也很符合 Python 的风格。
1
2
3
4
5
6
7
8
{'name': 'Hucci',
'birthdate': datetime.datetime(1960, 1, 1, 0, 0, tzinfo=datetime.timezone.utc),
'age': 59,
'sex': 'Female',
'hobbies': ['coding', 'swimming'],
'shape': {'height': 1, 'weight': 50},
'account': {'bilibili': {'username': 'hucciB', 'password': 'hucciBPW'},
'youtube': 'hucciY'}}
这个嵌套还可以继续嵌套下去,只要愿意加足够的 .
。
现在 social 这一项关于 bilibili 有两行,如果除了 username 和 password 我还想写什么关注数,网址链接等信息,看起来就会很杂乱。我们可以通过方括号的写法来合并同类项。
1
2
3
4
5
6
7
8
9
[account]
## bilibili.username = 'hucciB'
## bilibili.password = 'hucciBPW'
youtube = 'hucciY'
## 创建一张account中的bilibili的表
[account.bilibili]
username = 'hucciB'
password = 'hucciBPW'
这两种写法完全等价。
Table group
再介绍最后一种语法 table group。现在假设要给每一个平台,都用这样的格式说明 username 和 password,用包含字典的列表来写会非常方便。
1
2
3
4
account = [
{'platform'= 'bilibili', 'username'= 'hucciB', 'password'= 'hucciBPW'},
{'platform'= 'youtube', 'username'= 'hucciY', 'password'= 'hucciYPW'}
]
更 toml 的写法,是用两个方括号来说明是列表中的字典,就像这样。
1
2
3
4
5
6
7
8
9
[[account]]
platform = 'bilibili'
username = 'hucciB'
password = 'hucciBPW'
[[account]]
platform = 'youtube'
username = 'hucciY'
password = 'hucciYPW'
到这里,我们就介绍完了 toml 的所有基本语法。
为什么要用专门的配置语言
你可能会奇怪,明明可以直接用 python 写 config,为什么要用专门的配置语言呢?我之前在介绍 .env
文件存储环境变量时,也遇到了这样的疑问。
最主要是从安全性考虑。Python 文件是可执行代码,我们 import 时候会执行这些代码,存在一定安全隐患;而 YAML/JSON/TOML 等等是纯数据,避免了执行代码的风险。
Outro
最后总结一下,我们介绍了配置语言 toml 的语法,说明为什么它适合 Python,并说明为什么要用专门的配置语言而不是用 Python 写 config。