持续优化 8 年,这种自动化配置开始广受欢迎!

发布于 更新于
本文目录
  1. 1. 一个小例子
  2. 2. 字符串
  3. 3.数字
  4. 4. 布尔
  5. 5. 时间
  6. 6. 数组
  7. 7. 哈希表
  8. 表和数组的配套使用

技术文章

今天我们一起来学习 toml 这种简洁的配置文件格式吧。TOML 是在 2013 年发布的配置文件格式。距今虽然有 8 年历史了,但是之前一直没有在大项目中见过的。我是前段时间在看 python 的 pep 规范,无意中看到了这种配置文件格...

今天我们一起来学习 toml 这种简洁的配置文件格式吧。

TOML 是在 2013 年发布的配置文件格式。距今虽然有 8 年历史了,但是之前一直没有在大项目中见过的。我是前段时间在看 python 的 pep 规范,无意中看到了这种配置文件格式,稍微了解了一下,才发现现在有很多新的明星项目都喜欢用它来做配置文件。

  • 有 rust 语言的包管理工具 cargo;

  • 类似于 docker 的容器工具 containerd;

  • go 语言很多项目都喜欢用。比如静态网站生成工具 Hugo、数据库 InfluxDB、GitLab CI。

  • python 项目也开始接纳。包管理工具 pip、pipenv 和 Poetry 都是用的 TOML,1现在连官方的 metadata 管理也开始支持 toml。



1. 一个小例子

为什么新项目这么喜欢 TOML 呢?让我们先来看一个 TOML 的小例子吧,看完了说不定你就知道了。


[project]
name = "spam"
version = "2020.0.0"
description = "Lovely Spam! Wonderful Spam!"
readme = "README.rst"
requires-python = ">=3.8"
license = {file = "LICENSE.txt"}
keywords = ["egg", "bacon", "sausage"]


有没有感觉很熟悉呢?它和 ini 格式的配置文件几乎一模一样。要知道互联网发展到今天,大多数有影响力的项目都是采用 ini 这种配置文件格式,如果你之前有接触过 ini,切换到 toml 几乎是 0 成本。
那为什么不直接用 ini 呢?因为 ini 格式支持的数据类型非常少,配置项的值都会被默认当成字符串,如果想表示数字、数组,还需要自己进行额外的解析。
但是在 TOML 中,数据类型非常丰富:

  • 字符串

  • 注释

  • 数字

  • 布尔值

  • 数组

  • 哈希表

  • 甚至连时间格式都支持



2. 字符串

字符串我们当然不会陌生,但是如果你是从 ini 格式转过来的,一定要注意字符串值要加引号。
键默认会当成字符串处理,可以加也可以不加。加引号的键叫引号键(Quoted Key),不加引号的键叫裸键(Bare Key)。
TOML 格式非常灵活,对于灵活的语言,最好的方式是给自己设置规范和纪律,一直用好一种用法,不然很容易学废。官方推荐我们尽量用裸键,当裸键不能正确表达意思的时候,再用引号键。
name = "spam"     #OK
name_1 = spam     #错误
"name_2" = "spam" #OK


裸键只能包含 ASCII 字母,ASCII 数字,下划线和短横线(A-Za-z0-9_-),引号键则可以支持特殊字符,甚至是空格。当键中包含特殊字符的时候,使用引号键。


'name@! erf:' = 'spam' # OK
name@! erf: = 'spam'   # 错误


当字符串为多行字符串时使用三引号,会自动换行:
name = """
this is a
new line 
command"""


得到的结果是:
this is a
new line
command


如果不想自动换行,只是想增强可读性,可以使用折行符号 \:
name = """
this is a \
new line \
command"""


得到结果是不换行的:
this is a new line command


3.数字

如果你都会编程了,数字应该会知道怎么表示。
age1 = 18
age2 = -2
age3 = +16
age4 = 11.2


toml 除了支持 10 进制表示,还支持二进制(0b)、八进制(0o)、十六进制(0x)
age1 = 0b11
age2 = 0o12
age3 = 0xb


上面的解析结果为:
{
    'age1': 3, 
     'age2': 10, 
     'age3': 11
}


4. 布尔

bool1 = true
bool2 = false


5. 时间

时间类型是 toml 的一大特色,因为绝大多数的配置文件格式都是不支持时间类型的。toml 遵循的是 RFC 3339 时间格式,只要照着格式写,解析出来会自动转成编程语言的时间类型。


ts = 2021-01-06 07:30:00
ts1 = 2021-01-06 07:30:00.1234
time1 = 07:30:00


得到的结果:

{
    'ts': datetime.datetime(2021, 1, 6, 7, 30), 
     'ts1': datetime.datetime(2021, 1, 6, 7, 30, 0, 123000),
    'time1': datetime.time(7, 30)
}


6. 数组

数组可以是同类型数据,可以换行,也可以嵌套,和 python 当中列表简直一模一样。但是要注意,尽量保持元素是同类型的数据。
users = [
    ['iswy', '男'],
    ['you', '女'],
]


得到结果:
{
    'users': [
        ['iswy', '男'], 
        ['you', '女']
    ]
}


7. 哈希表

表有点类似于 python 中的字典:
user = {name='iswy', gender='男'}
得到的结果:
{
    'user': {
        'gender': '男', 
        'name': 'iswy'
    }
}

这种写在 key 后面的表叫内联表。还有一种用法,类似于 ini 格式中的 section,用于分组管理,暂且把它叫做外联表。比如上面的例子,可以换一种形式,得到的结果是完全一样的。

[user]
gender = '男'
name = 'iswy'
表支持嵌套,子表可以缩进也可以不缩进:

[user]
    cat = ['admin', 'normal']

    [user.student]
    name='iswy'
    age=19

    [user.teacher]
    name='you'
    age=32

如果你觉得这种风格你不喜欢,也可以换成下面的风格:

[user]
cat = ['admin', 'normal']

# student
student.name='iswy'
student.age=19

# teacher
teacher.name='you'
teacher.age=328

一定要注意,当键包含 . 号时,一定要加引号:
site.'x.com' = 'https://x.com'


我个人更倾向于子表嵌套的风格,因为这样的表述看起来更加简洁。

表和数组的配套使用

最后我们要考虑的问题是当有多个用户需要配置,我们要使用表数组进行分组呢?

[[user]]

    [user.student]
    name='iswy'
    age=19

    [user.teacher]
    name='you'
    age=328

[[user]]
    [user.student]
    name='iswy2'
    age=192

    [user.teacher]
    name='you2'
    age=3282

得到的结果:

{
    'user': [
        {
            'student': {'age': 19, 'name': 'iswy'},
             'teacher': {'age': 328, 'name': 'you'}
        },
        {
            'student': {'age': 192, 'name': 'iswy2'},
            'teacher': {'age': 3282, 'name': 'you2'}
        }
    ]
}


使用 python 语言解析 toml :

import toml

with open('api.toml', encoding='utf-8') as f:
    data = toml.loads(f.read())


继续阅读