Python解析toml配置文件的方法分享
楔子
上一篇文章我們介紹了 yaml,雖然 yaml 的表達能力已經(jīng)很豐富了,但 GitHub 覺得還是不夠優(yōu)雅,所以鼓搗出了一個 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 的數(shù)據(jù)結構。
注釋
toml 采用 # 表示注釋,舉個例子:
#?這是注釋 key?=?"value"??#?也是注釋
可以解析一下看看會得到什么,劇透:會得到只包含一個鍵值對的字典。
鍵值對
TOML 文檔最基本的構成區(qū)塊是鍵值對,鍵名在等號的左邊、值在右邊,并且鍵名和鍵值周圍的空白會被忽略。此外鍵、等號和值必須在同一行(不過有些值可以跨多行)。
key?=?"value"
鍵名可以是裸露的(裸鍵),引號引起來的(引號鍵),或點分隔的(點分隔鍵)。裸鍵只能包含:ascii 字符、ascii 數(shù)字、下劃線、短橫線。
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}}}
}
"""我們看到這個點分隔符不錯喲,自動實現(xiàn)了嵌套結構,并且點分隔符周圍的空白會被忽略。
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#?此時可以繼續(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
#?但接下來就不合法了,因為整數(shù)不能變成字典
fruit.apple.smooth?=?true
#?如果我們設置?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'}
"""如果鍵是浮點數(shù),那么需要使用引號括起來,否則會被解釋為點分隔鍵。
看完了鍵,再來看看值(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'}
"""這里的引號可以是雙引號、也可以是單引號。
整數(shù)
整數(shù)是純數(shù)字,正數(shù)可以有加號前綴,負數(shù)的前綴是減號。
import?toml
config?=?"""
int1?=?+99
int2?=?42
int3?=?0
int4?=?-17
#?對于大數(shù),可以在數(shù)字之間用下劃線來增強可讀性
#?每個下劃線兩側必須至少有一個數(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 本身。當然 -0 與 +0 也是有效的,并等同于無前綴的零。非負整數(shù)值也可以用十六進制、八進制或二進制來表示。
#?帶有?`0x`?前綴的十六進制,大小寫均可 hex1?=?0xDEADBEEF hex2?=?0xdeadbeef hex3?=?0xdead_beef #?帶有?`0o`?前綴的八進制 oct1?=?0o01234567 oct2?=?0o755?#?對于表示?Unix?文件權限很有用 #?帶有?`0b`?前綴的二進制 bin1?=?0b11010110
浮點數(shù)
一個浮點數(shù)由一個整數(shù)部分(遵從與十進制整數(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ù)點后跟一個或多個數(shù)字,一個指數(shù)部分是一個 E(大小寫均可)后跟一個整數(shù)部分(遵從與十進制整數(shù)值相同的規(guī)則,但可以包含前導零)。小數(shù)點,如果有用到的話,每側必須緊鄰至少一個數(shù)字。
#?非法的浮點數(shù) invalid_float_1?=?.7 invalid_float_2?=?7. invalid_float_3?=?3.e+20
與整數(shù)相似,可以使用下劃線來增強可讀性,每個下劃線必須被至少一個數(shù)字圍繞。
flt8?=?224_617.445_991_228
浮點數(shù)值 -0.0 與 +0.0 是有效的,并且應當遵從 IEEE 754。特殊浮點值也能夠表示:
#?無窮 sf1?=?inf??#?正無窮 sf2?=?+inf?#?正無窮 sf3?=?-inf?#?負無窮 #?非數(shù) sf4?=?nan??#?是對應信號非數(shù)碼還是靜默非數(shù)碼,取決于實現(xiàn) sf5?=?+nan?#?等同于?`nan` sf6?=?-nan?#?正確,實際碼取決于實現(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?也是一個表,在它下方
#?直至下一個表頭或文件結束,都是這個表內部的鍵值對
[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}}
"""但是我們之前也實現(xià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īng)猜到了,它們被當成了 'table-2' 對應的字典里面的 key 了。此外我們還可以將上面兩種方式結合起來:
import?toml
config?=?"""
#?[]?里面的不再是一個普通的鍵,而是點分隔鍵
#?另外鍵名周圍的空格會被忽略,但是最好不要有
[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':?{}}}}}
????}
}
"""總的來說還是蠻強大的,但是要注意:不能重復定義。
行內表
行內表提供了一種更為緊湊的語法來表示表,因為上面每一個鍵值對都需要單獨寫一行,比如:
[table1]
a?=?1
b?=?2
c?=?3
#?最終可以得到?
#?{'table1':?{'a':?1,?'b':?2,?'c':?3}}但是除了上面的表達方式之外,我們還可以采用行內表:
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ù)組和表的結合:
import?toml
config?=?"""
[name1]
girl?=?"古明地覺"
[[name2]]
girl?=?"古明地戀"
[name3]
[[name4]]
"""
data?=?toml.loads(config)
print(data)
"""
{'name1':?{'girl':?'古明地覺'},
?'name2':?[{'girl':?'古明地戀'}],
?'name3':?{},
?'name4':?[{}]}
"""當使用 [[]] 的時候,相當于在 [] 的基礎上套上一層列表。并且任何對表數(shù)組的引用都指向該數(shù)組里最近定義的表元素,這允許我們在最近的表內定義子表,甚至子表數(shù)組。
我們再舉個更復雜的例子:
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':?'車前草'}]
????????????}
????????]
}
"""很明顯這種定義不是很常用,配置文件應該要非常直觀才對,但這已經(jīng)不是很好理解了。
以上就是Python解析toml配置文件的方法分享的詳細內容,更多關于Python解析toml的資料請關注腳本之家其它相關文章!
相關文章
Python urlencode和unquote函數(shù)使用實例解析
這篇文章主要介紹了Python urlencode和unquote函數(shù)使用實例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-03-03
Python Django框架url反向解析實現(xiàn)動態(tài)生成對應的url鏈接示例
這篇文章主要介紹了Python Django框架url反向解析實現(xiàn)動態(tài)生成對應的url鏈接,結合實例形式分析了Django框架URL反向解析具體原理與應用操作技巧,需要的朋友可以參考下2019-10-10
使用PIL(Python-Imaging)反轉圖像的顏色方法
今天小編就為大家分享一篇使用PIL(Python-Imaging)反轉圖像的顏色方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-01-01
用Python的Flask框架結合MySQL寫一個內存監(jiān)控程序
這篇文章主要介紹了用Python的Flask框架結合MySQL些一個內存監(jiān)控程序的例子,并且能將結果作簡單的圖形化顯示,需要的朋友可以參考下2015-11-11
解決新版Pycharm中Matplotlib圖像不在彈出獨立的顯示窗口問題
今天小編就為大家分享一篇解決新版Pycharm中Matplotlib圖像不在彈出獨立的顯示窗口問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-01-01

