溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么用Python解析toml配置文件

發(fā)布時間:2022-09-19 14:13:00 來源:億速云 閱讀:275 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“怎么用Python解析toml配置文件”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

舉個例子

有了 ini 和 yaml,相信 toml 學(xué)習(xí)來也很簡單,先直接看一個例子吧。

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 的形式進(jìn)行配置,然后也有類似于 ini 里面的 section,每個 section 都是字典中的一個 key,然后該 key 也對應(yīng)一個字典。但是我們注意看最開始的 title,由于它上面沒有 section,所以它是一個單獨(dú)的 key。

而且還有一點(diǎn)就是 toml 支持嵌套,我們看到 server.v1,表示 v1 是 server 對應(yīng)的字典里面的一個 key,然后 v1 對應(yīng)的值還是一個字典。

toml 變得更加簡單了,而且寫來也非常像 Python,它有如下特點(diǎn):

toml 文件是大小寫敏感的;

toml 文件必須是有效的 UTF-8 編碼的 Unicode 文檔;

toml 文件的空白符應(yīng)該是 Tab 或者空格;

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

然后我們來介紹一下 toml 的數(shù)據(jù)結(jié)構(gòu)。

注釋

toml 采用 # 表示注釋,舉個例子:

# 這是注釋
key = "value"  # 也是注釋

可以解析一下看看會得到什么,劇透:會得到只包含一個鍵值對的字典。

鍵值對

TOML 文檔最基本的構(gòu)成區(qū)塊是鍵值對,鍵名在等號的左邊、值在右邊,并且鍵名和鍵值周圍的空白會被忽略。此外鍵、等號和值必須在同一行(不過有些值可以跨多行)。

key = "value"

鍵名可以是裸露的(裸鍵),引號引起來的(引號鍵),或點(diǎn)分隔的(點(diǎn)分隔鍵)。裸鍵只能包含:ascii 字符、ascii 數(shù)字、下劃線、短橫線。

import toml

config = """
key = "value"
bare_key = "value"
bare-key = "value"
# 1234 會被當(dāng)成字符串
1234 = "value"  
"""

data = toml.loads(config)
print(data)
"""
{'key': 'value', 
 'bare_key': 'value', 
 'bare-key': 'value', 
 '1234': 'value'}
"""

如果不是裸鍵,那么就必須使用引號括起來,但是此時也支持我們使用更加廣泛的鍵名,但除了特殊場景,否則使用裸鍵是最佳實(shí)踐。

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'}
"""

注意:裸鍵不能為空,但空引號鍵是允許的(雖然不建議如此)。

= "沒有鍵名"  # 錯誤
"" = "空"     # 正確但不鼓勵
'' = '空'     # 正確但不鼓勵

然后是點(diǎn)分隔鍵,它是一系列通過點(diǎn)相連的裸鍵或引號鍵,這允許我們將相近屬性放在一起:

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}}}
}
"""

我們看到這個點(diǎn)分隔符不錯喲,自動實(shí)現(xiàn)了嵌套結(jié)構(gòu),并且點(diǎn)分隔符周圍的空白會被忽略。

fruit.name = "香蕉"     # 這是最佳實(shí)踐
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)
"""

對于點(diǎn)分隔鍵也是如此,只要一個鍵還沒有被直接定義過,我們就仍可以對它和它下屬的鍵名賦值。

import toml

config = """
fruit.apple.smooth = true# 此時可以繼續(xù)操作 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 的值定義為一個整數(shù)
fruit.apple = 1
# 但接下來就不合法了,因?yàn)檎麛?shù)不能變成字典
fruit.apple.smooth = true

# 如果我們設(shè)置 fruit.apple = {},那么第二個賦值是可以的
# 沒錯,我們可以通過 {} 直接創(chuàng)建一個字典

可以看到,真的很像 Python。然后再來說一個特例:

import toml

config = """
3.14 = "pi"  
"3.14" = "pi"  
"""

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

如果鍵是浮點(diǎn)數(shù),那么需要使用引號括起來,否則會被解釋為點(diǎn)分隔鍵。

看完了鍵,再來看看值(value),其實(shí)對于 toml 來說,值比鍵要簡單的多得多。

字符串

字符串共有四種方式來表示:基礎(chǔ)式的,多行基礎(chǔ)式的,字面量式的,和多行字面量式的。

1)基礎(chǔ)字符串由引號包裹,任何 Unicode 字符都可以使用,除了那些必須轉(zhuǎn)義的。

import toml

config = """
str = '我是一個字符串,"你可以把我引起來"' 
"""

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

2)多行字符串由三個引號包裹,允許換行,注意:緊隨開頭引號的換行會被去除,其它空白和換行會被原樣保留。

import toml

config = """
str = '''
玫瑰是紅色的
紫羅蘭是藍(lán)色的
'''
"""

data = toml.loads(config)
print(data)
"""
{'str': '玫瑰是紅色的\n紫羅蘭是藍(lán)色的\n'}
"""

這里的引號可以是雙引號、也可以是單引號。

整數(shù)

整數(shù)是純數(shù)字,正數(shù)可以有加號前綴,負(fù)數(shù)的前綴是減號。

import toml

config = """
int1 = +99
int2 = 42
int3 = 0
int4 = -17

# 對于大數(shù),可以在數(shù)字之間用下劃線來增強(qiáng)可讀性
# 每個下劃線兩側(cè)必須至少有一個數(shù)字。
int5 = 1_000
int6 = 5_349_221
int7 = 53_49_221  # 印度記數(shù)體系分組
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}
"""

但是注意:數(shù)字不能以零開頭,除了 0 本身。當(dāng)然 -0 與 +0 也是有效的,并等同于無前綴的零。非負(fù)整數(shù)值也可以用十六進(jìn)制、八進(jìn)制或二進(jìn)制來表示。

# 帶有 `0x` 前綴的十六進(jìn)制,大小寫均可
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef

# 帶有 `0o` 前綴的八進(jìn)制
oct1 = 0o01234567
oct2 = 0o755 # 對于表示 Unix 文件權(quán)限很有用

# 帶有 `0b` 前綴的二進(jìn)制
bin1 = 0b11010110

浮點(diǎn)數(shù)

一個浮點(diǎn)數(shù)由一個整數(shù)部分(遵從與十進(jìn)制整數(shù)值相同的規(guī)則)后跟上一個小數(shù)部分、或一個指數(shù)部分組成。如果小數(shù)部分和指數(shù)部分兼有,那小數(shù)部分必須在指數(shù)部分前面。

import toml

config = """
# 小數(shù)
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01

# 指數(shù)
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}
"""

小數(shù)部分是一個小數(shù)點(diǎn)后跟一個或多個數(shù)字,一個指數(shù)部分是一個 E(大小寫均可)后跟一個整數(shù)部分(遵從與十進(jìn)制整數(shù)值相同的規(guī)則,但可以包含前導(dǎo)零)。小數(shù)點(diǎn),如果有用到的話,每側(cè)必須緊鄰至少一個數(shù)字。

# 非法的浮點(diǎn)數(shù)
invalid_float_1 = .7
invalid_float_2 = 7.
invalid_float_3 = 3.e+20

與整數(shù)相似,可以使用下劃線來增強(qiáng)可讀性,每個下劃線必須被至少一個數(shù)字圍繞。

flt8 = 224_617.445_991_228

浮點(diǎn)數(shù)值 -0.0 與 +0.0 是有效的,并且應(yīng)當(dāng)遵從 IEEE 754。特殊浮點(diǎn)值也能夠表示:

# 無窮
sf1 = inf  # 正無窮
sf2 = +inf # 正無窮
sf3 = -inf # 負(fù)無窮

# 非數(shù)
sf4 = nan  # 是對應(yīng)信號非數(shù)碼還是靜默非數(shù)碼,取決于實(shí)現(xiàn)
sf5 = +nan # 等同于 `nan`
sf6 = -nan # 正確,實(shí)際碼取決于實(shí)現(xiàn)

布爾值

布爾值就是慣用的那樣,但要小寫。

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)}
"""

數(shù)組

語法和 Python 的列表類似:

import toml

config = """
# 每個數(shù)組里面的元素類型要一致
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]}
"""

數(shù)組可以跨行,數(shù)組的最后一個值后面可以有終逗號(也稱為尾逗號)。

import toml

config = """
integers2 = [
  1, 2, 3
]

integers3 = [
  1,
  2, # 這是可以的
]
"""

data = toml.loads(config)
print(data)
"""
{'integers2': [1, 2, 3], 'integers3': [1, 2]}
"""

表,完全可以把它想象成 ini 的 section。

import toml

config = """
# 表名的定義規(guī)則與鍵名相同
# 解析之后得到的大字典中就有 "table-1" 這個 key
# 并且其 value 也是一個表,在它下方
# 直至下一個表頭或文件結(jié)束,都是這個表內(nèi)部的鍵值對
[table-1]
key1 = "some string"
key2 = 123

[table-2]
key1 = "another string"
key2 = 456
"""

data = toml.loads(config)
print(data)
"""
{'table-1': {'key1': 'some string', 'key2': 123},
 'table-2': {'key1': 'another string', 'key2': 456}}
"""

但是我們之前也實(shí)現(xiàn)過類似于這種結(jié)構(gòu),沒錯,就是點(diǎn)分隔符:

import toml

config = """
# 所以 other-table-1 和 table-1 是等價的
# other-table-2 和 table-2 是等價的
other-table-1.key1 = "some string"
other-table-1.key2 = 123

other-table-2.key1 = "another string"
other-table-2.key2 = 456

[table-1]
key1 = "some string"
key2 = 123

[table-2]
key1 = "another string"
key2 = 456
"""

data = toml.loads(config)
print(data)
"""
{'other-table-1': {'key1': 'some string', 'key2': 123},
 'other-table-2': {'key1': 'another string', 'key2': 456},
 'table-1': {'key1': 'some string', 'key2': 123},
 'table-2': {'key1': 'another string', 'key2': 456}}
"""

不過注意:我們必須要把 other-table-1 和 other-table-2 定義在上面,如果我們定義在下面看看會有什么后果:

import toml

config = """
[table-1]
key1 = "some string"
key2 = 123

[table-2]
key1 = "another string"
key2 = 456

other-table-1.key1 = "some string"
other-table-1.key2 = 123

other-table-2.key1 = "another string"
other-table-2.key2 = 456
"""

data = toml.loads(config)
print(data)
"""
{
    'table-1': {'key1': 'some string', 'key2': 123},
    'table-2': {'key1': 'another string',
                'key2': 456,
                'other-table-1': {'key1': 'some string', 
                                  'key2': 123},
                'other-table-2': {'key1': 'another string', 
                                  'key2': 456}}
}
"""

估計(jì)你已經(jīng)猜到了,它們被當(dāng)成了 'table-2' 對應(yīng)的字典里面的 key 了。此外我們還可以將上面兩種方式結(jié)合起來:

import toml

config = """
# [] 里面的不再是一個普通的鍵,而是點(diǎn)分隔鍵
# 另外鍵名周圍的空格會被忽略,但是最好不要有
[dog  .  "tater.man"]  
type.name = "哈巴狗"
"""

data = toml.loads(config)
print(data)
"""
{
    'dog': {'tater.man': {'type': {'name': '哈巴狗'}}}
}
"""

表的里面也是可以沒有鍵值對的:

import toml

config = """
[x.y.z.w.a.n]

[x.m]

[x.n]

[x]
a.b.c = "xxx"
"""

data = toml.loads(config)
print(data)
"""
{'x':
    {
        'a': {'b': {'c': 'xxx'}},
        'm': {},
        'n': {},
        'y': {'z': {'w': {'a': {'n': {}}}}}
    }
}
"""

總的來說還是蠻強(qiáng)大的,但是要注意:不能重復(fù)定義。

行內(nèi)表

行內(nèi)表提供了一種更為緊湊的語法來表示表,因?yàn)樯厦婷恳粋€鍵值對都需要單獨(dú)寫一行,比如:

[table1]
a = 1
b = 2
c = 3
# 最終可以得到 
# {'table1': {'a': 1, 'b': 2, 'c': 3}}

但是除了上面的表達(dá)方式之外,我們還可以采用行內(nèi)表:

import toml

config = """
# 和 Python 字典的表示方式略有不同
# 并且也支持多種 key
table1 = {a = 1, b = "二", c.a = "3"}
table2 = {c."b c".d = "4"}
"""

data = toml.loads(config)
print(data)
"""
{
    'table1': {'a': 1, 'b': '二', 'c': {'a': '3'}},
    'table2': {'c': {'b c': {'d': '4'}}}
}
"""

表數(shù)組

然后來看看數(shù)組和表的結(jié)合:

import toml

config = """
[name1]
girl = "古明地覺"

[[name2]]
girl = "古明地戀"

[name3]
[[name4]]
"""

data = toml.loads(config)
print(data)
"""
{'name1': {'girl': '古明地覺'},
 'name2': [{'girl': '古明地戀'}],
 'name3': {},
 'name4': [{}]}
"""

當(dāng)使用 [[]] 的時候,相當(dāng)于在 [] 的基礎(chǔ)上套上一層列表。并且任何對表數(shù)組的引用都指向該數(shù)組里最近定義的表元素,這允許我們在最近的表內(nèi)定義子表,甚至子表數(shù)組。

我們再舉個更復(fù)雜的例子:

import toml

config = """
[[fruits]]  
name = "蘋果"  

# 會操作 [] 里面最近定義的 {}
[fruits.physical]  
color = "紅色"
shape = "圓形"

[[fruits.varieties]]  # 嵌套表數(shù)組
name = "蛇果"    

[[fruits.varieties]]
name = "澳洲青蘋" 

[[fruits]]
name = "香蕉" 

[[fruits.varieties]]
name = "車前草"  
"""

data = toml.loads(config)
print(data)
"""
{
    'fruits':
        [
            {
                'name': '蘋果',
                'physical': {'color': '紅色', 
                             'shape': '圓形'},
                'varieties': [{'name': '蛇果'}, 
                              {'name': '澳洲青蘋'}]
            },
            {
                'name': '香蕉', 
                'varieties': [{'name': '車前草'}]
            }
        ]
}
"""

很明顯這種定義不是很常用,配置文件應(yīng)該要非常直觀才對,但這已經(jīng)不是很好理解了。

“怎么用Python解析toml配置文件”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI