Python解析toml配置文件的方法分享
楔子
上一篇文章我們介紹了 yaml,雖然 yaml 的表達(dá)能力已經(jīng)很豐富了,但 GitHub 覺得還是不夠優(yōu)雅,所以鼓搗出了一個 toml。toml 有著比 yaml 更簡潔的語法,它的目標(biāo)就是成為一個最簡單的配置文件格式。
然后 Python 解析 toml 文件需要使用一個名字也叫 toml 的庫,直接 pip install toml 即可。
舉個例子
有了 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ī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配置文件的方法分享的詳細(xì)內(nèi)容,更多關(guān)于Python解析toml的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python urlencode和unquote函數(shù)使用實(shí)例解析
這篇文章主要介紹了Python urlencode和unquote函數(shù)使用實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03Python Django框架url反向解析實(shí)現(xiàn)動態(tài)生成對應(yīng)的url鏈接示例
這篇文章主要介紹了Python Django框架url反向解析實(shí)現(xiàn)動態(tài)生成對應(yīng)的url鏈接,結(jié)合實(shí)例形式分析了Django框架URL反向解析具體原理與應(yīng)用操作技巧,需要的朋友可以參考下2019-10-10使用PIL(Python-Imaging)反轉(zhuǎn)圖像的顏色方法
今天小編就為大家分享一篇使用PIL(Python-Imaging)反轉(zhuǎn)圖像的顏色方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-01-01通過gradio和攝像頭獲取照片和視頻實(shí)現(xiàn)過程
這篇文章主要為大家介紹了gradio和攝像頭獲取照片和視頻實(shí)現(xiàn)過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04用Python的Flask框架結(jié)合MySQL寫一個內(nèi)存監(jiān)控程序
這篇文章主要介紹了用Python的Flask框架結(jié)合MySQL些一個內(nèi)存監(jiān)控程序的例子,并且能將結(jié)果作簡單的圖形化顯示,需要的朋友可以參考下2015-11-11解決新版Pycharm中Matplotlib圖像不在彈出獨(dú)立的顯示窗口問題
今天小編就為大家分享一篇解決新版Pycharm中Matplotlib圖像不在彈出獨(dú)立的顯示窗口問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-01-01