您现在的位置是:网站首页> 编程资料编程资料

Python解析toml配置文件的方法分享_python_

2023-05-26 398人已围观

简介 Python解析toml配置文件的方法分享_python_

楔子

上一篇文章我们介绍了 yaml,虽然 yaml 的表达能力已经很丰富了,但 GitHub 觉得还是不够优雅,所以鼓捣出了一个 toml。toml 有着比 yaml 更简洁的语法,它的目标就是成为一个最简单的配置文件格式。

然后 Python 解析 toml 文件需要使用一个名字也叫 toml 的库,直接 pip install toml 即可。

举个例子

有了 ini 和 yaml,相信 toml 学习来也很简单,先直接看一个例子吧。

import toml config = """ title = "toml 小栗子" [owner] name = "古明地觉" age = 17 place = "东方地灵殿" nickname = ["小五", "少女觉", "觉大人"] [database] host = "127.0.0.1" port = 5432 username = "satori" password = "123456" echo = true [server]     [server.v1]     api = "1.1"     enable = false          [server.v2]     api = "1.2"     enable = true [client] client = [     ["socket", "webservice"],      [5555] ] address = [     "xxxx",     "yyyy" ] """ # loads:从字符串加载 # load:从文件加载 # dumps:生成 toml 格式字符串 # dump:生成 toml 格式字符串并写入文件中 data = toml.loads(config) print(data) """ {     'title': 'toml 小栗子',      'owner': {'name': '古明地觉',                'age': 17,                'place': '东方地灵殿',                'nickname': ['小五', '少女觉', '觉大人']},     'database': {'host': '127.0.0.1',                   'port': 5432,                  'username': 'satori',                   'password': '123456',                   'echo': True},     'server': {'v1': {'api': '1.1', 'enable': False},                 'v2': {'api': '1.2', 'enable': True}},     'client': {'client': [['socket', 'webservice'], [5555]],                 'address': ['xxxx', 'yyyy']} } """

toml 是采用 var = value 的形式进行配置,然后也有类似于 ini 里面的 section,每个 section 都是字典中的一个 key,然后该 key 也对应一个字典。但是我们注意看最开始的 title,由于它上面没有 section,所以它是一个单独的 key。

而且还有一点就是 toml 支持嵌套,我们看到 server.v1,表示 v1 是 server 对应的字典里面的一个 key,然后 v1 对应的值还是一个字典。

toml 变得更加简单了,而且写来也非常像 Python,它有如下特点:

toml 文件是大小写敏感的;

toml 文件必须是有效的 UTF-8 编码的 Unicode 文档;

toml 文件的空白符应该是 Tab 或者空格;

toml 文件的换行是 LF 或者 CRLF;

然后我们来介绍一下 toml 的数据结构。

注释

toml 采用 # 表示注释,举个例子:

# 这是注释 key = "value"  # 也是注释

可以解析一下看看会得到什么,剧透:会得到只包含一个键值对的字典。

键值对

TOML 文档最基本的构成区块是键值对,键名在等号的左边、值在右边,并且键名和键值周围的空白会被忽略。此外键、等号和值必须在同一行(不过有些值可以跨多行)。

key = "value"

键名可以是裸露的(裸键),引号引起来的(引号键),或点分隔的(点分隔键)。裸键只能包含:ascii 字符、ascii 数字、下划线、短横线。

import toml config = """ key = "value" bare_key = "value" bare-key = "value" # 1234 会被当成字符串 1234 = "value"   """ data = toml.loads(config) print(data) """ {'key': 'value',   'bare_key': 'value',   'bare-key': 'value',   '1234': 'value'} """

如果不是裸键,那么就必须使用引号括起来,但是此时也支持我们使用更加广泛的键名,但除了特殊场景,否则使用裸键是最佳实践。

import toml config = """ "127.0.0.1" = "value" "character encoding" = "value" "ʎǝʞ" = "value" 'key2' = "value" 'quoted "value"' = "value"  """ data = toml.loads(config) print(data) """ {'127.0.0.1': 'value',   'character encoding': 'value',   'ʎǝʞ': 'value',   'key2': 'value',   'quoted "value"': 'value'} """

注意:裸键不能为空,但空引号键是允许的(虽然不建议如此)。

= "没有键名"  # 错误 "" = "空"     # 正确但不鼓励 '' = '空'     # 正确但不鼓励

然后是点分隔键,它是一系列通过点相连的裸键或引号键,这允许我们将相近属性放在一起:

import toml config = """ name = "橙子" physical.color = "橙色" physical.shape = "圆形" site."google.com" = true site.google.com = true a.b.c.d = 123 """ data = toml.loads(config) print(data) """ {     'name': '橙子',     'physical': {'color': '橙色',                  'shape': '圆形'},     'site': {'google.com': True,              'google': {'com': True}},     'a': {'b': {'c': {'d': 123}}} } """

我们看到这个点分隔符不错哟,自动实现了嵌套结构,并且点分隔符周围的空白会被忽略。

fruit.name = "香蕉"     # 这是最佳实践 fruit. color = "黄色"    # 等同于 fruit.color fruit . flavor = "香蕉"   # 等同于 fruit.flavor

注意:多次定义同一个键是不行的。

import toml config = """ # name 和 "name" 是等价的 name = "古明地觉" "name" = "古明地恋"   """ try:     data = toml.loads(config) except toml.decoder.TomlDecodeError as e:     print(e) """ Duplicate keys! (line 4 column 1 char 36) """

对于点分隔键也是如此,只要一个键还没有被直接定义过,我们就仍可以对它和它下属的键名赋值。

import toml config = """ fruit.apple.smooth = true# 此时可以继续操作 fruit、fruit.apple,它们都是字典 # 给 fruit 这个字典加一个 key   fruit.orange = 2   # 给 fruit.apple 加一个 key fruit.apple.color = "red"    """ data = toml.loads(config) print(data) """ {     'fruit': {'apple': {'smooth': True,                          'color': 'red'},                'orange': 2} } """

但下面这个操作是不行的:

# 将 fruit.apple 的值定义为一个整数 fruit.apple = 1 # 但接下来就不合法了,因为整数不能变成字典 fruit.apple.smooth = true # 如果我们设置 fruit.apple = {},那么第二个赋值是可以的 # 没错,我们可以通过 {} 直接创建一个字典

可以看到,真的很像 Python。然后再来说一个特例:

import toml config = """ 3.14 = "pi"   "3.14" = "pi"   """ data = toml.loads(config) print(data) """ {'3': {'14': 'pi'}, '3.14': 'pi'} """

如果键是浮点数,那么需要使用引号括起来,否则会被解释为点分隔键。

看完了键,再来看看值(value),其实对于 toml 来说,值比键要简单的多得多。

字符串

字符串共有四种方式来表示:基础式的,多行基础式的,字面量式的,和多行字面量式的。

1)基础字符串由引号包裹,任何 Unicode 字符都可以使用,除了那些必须转义的。

import toml config = """ str = '我是一个字符串,"你可以把我引起来"'  """ data = toml.loads(config) print(data) """ {'str': '我是一个字符串,"你可以把我引起来"'} """

2)多行字符串由三个引号包裹,允许换行,注意:紧随开头引号的换行会被去除,其它空白和换行会被原样保留。

import toml config = """ str = ''' 玫瑰是红色的 紫罗兰是蓝色的 ''' """ data = toml.loads(config) print(data) """ {'str': '玫瑰是红色的\n紫罗兰是蓝色的\n'} """

这里的引号可以是双引号、也可以是单引号。

整数

整数是纯数字,正数可以有加号前缀,负数的前缀是减号。

import toml config = """ int1 = +99 int2 = 42 int3 = 0 int4 = -17 # 对于大数,可以在数字之间用下划线来增强可读性 # 每个下划线两侧必须至少有一个数字。 int5 = 1_000 int6 = 5_349_221 int7 = 53_49_221  # 印度记数体系分组 int8 = 1_2_3_4_5  # 无误但不鼓励 """ data = toml.loads(config) print(data) """ {'int1': 99,  'int2': 42,  'int3': 0,  'int4': -17,  'int5': 1000,  'int6': 5349221,  'int7': 5349221,  'int8': 12345} """

但是注意:数字不能以零开头,除了 0 本身。当然 -0 与 +0 也是有效的,并等同于无前缀的零。非负整数值也可以用十六进制、八进制或二进制来表示。

# 带有 `0x` 前缀的十六进制,大小写均可 hex1 = 0xDEADBEEF hex2 = 0xdeadbeef hex3 = 0xdead_beef # 带有 `0o` 前缀的八进制 oct1 = 0o01234567 oct2 = 0o755 # 对于表示 Unix 文件权限很有用 # 带有 `0b` 前缀的二进制 bin1 = 0b11010110

浮点数

一个浮点数由一个整数部分(遵从与十进制整数值相同的规则)后跟上一个小数部分、或一个指数部分组成。如果小数部分和指数部分兼有,那小数部分必须在指数部分前面。

import toml config = """ # 小数 flt1 = +1.0 flt2 = 3.1415 flt3 = -0.01 # 指数 flt4 = 5e+22 flt5 = 1e06 flt6 = -2E-2 flt7 = 6.626e-34 """ data = toml.loads(config) print(data) """ {'flt1': 1.0,  'flt2': 3.1415,  'flt3': -0.01,  'flt4': 5e+22,  'flt5': 1000000.0,  'flt6': -0.02,  'flt7': 6.626e-34} """

小数部分是一个小数点后跟一个或多个数字,一个指数部分是一个 E(大小写均可)后跟一个整数部分(遵从与十进制整数值相同的规则,但可以包含前导零)。小数点,如果有用到的话,每侧必须紧邻至少一个数字。

# 非法的浮点数 invalid_float_1 = .7 invalid_float_2 = 7. invalid_float_3 = 3.e+20

与整数相似,可以使用下划线来增强可读性,每个下划线必须被至少一个数字围绕。

flt8 = 224_617.445_991_228

浮点数值 -0.0 与 +0.0 是有效的,并且应当遵从 IEEE 754。特殊浮点值也能够表示:

# 无穷 sf1 = inf  # 正无穷 sf2 = +inf # 正无穷 sf3 = -inf # 负无穷 # 非数 sf4 = nan  # 是对应信号非数码还是静默非数码,取决于实现 sf5 = +nan # 等同于 `nan` sf6 = -nan # 正确,实际码取决于实现

布尔值

布尔值就是惯用的那样,但要小写。

bool1 = true bool2 = false

日期

可以是普通的 datetime,或者是遵循 ISO-8859-1 格式的日期。

import toml config = """ dt1 = 2020-01-01T12:33:22+00:00 dt2 = 2020-11-12 12:11:33 dt3 = 2020-11-23 """ data = toml.loads(config) print(data) """ {'dt1': datetime.datetime(2020, 1, 1, 12, 33, 22, tzinfo=...),   'dt2': datetime.datetime(2020, 11, 12, 12, 11, 33),   'dt3': datetime.date(2020, 11, 23)} """

数组

语法和 Python 的列表类似:

import toml config = """ # 每个数组里面的元素类型要一致 integers = [1, 2, 3] colors = ["红", "黄", "绿"] nested_array_of_ints = [[1, 2], [3, 4, 5]] nested_mixed_array = [[1, 2], ["a", "b", "c"]] numbers = [0.1, 0.2, 0.5] """ data = toml.loads(config) print(data) """ {'colors': ['红', '黄', '绿'],  'integers': [1, 2, 3],  'nested_array_of_ints': [[1, 2], [3, 4, 5]],  'nested_mixed_array': [[1, 2], ['a', 'b', 'c']],  'numbers': [0.1, 0.2, 0.5]} """

数组可以跨行,数组的最后一个值后面可以有终逗号(也称为尾逗号)。

import toml config = """ integers2 = [   1, 2, 3 ] integers3 = [   1,   2, # 这是可以的 ] """ data = toml.loads(config) print(data) """ {'integers2': [1, 2, 3], 'integers3': [1, 2]} """

-六神源码网