1. 程式人生 > 實用技巧 >PyYaml簡單學習

PyYaml簡單學習

YAML是一種輕型的配置檔案的語言,遠比JSON格式方便,方便人類讀寫,它通過縮排來表示結構,很具有Python風格。
安裝:pip insall pyyaml

YAML語法

  • 文件

YAML資料流是0個或者多個文件,文件之間用---分割,文件可選用...結束,單個文件可用也可不用---開頭。

隱式文件如下:

"""
- Multimedia
- Internet
- Education
"""
'\n- Multimedia\n- Internet\n- Education\n'

顯式文件如下:

"""
---
- Multimedia
- Internet
- Education
...
"""
'\n---\n- Multimedia\n- Internet\n- Education\n...\n'
  • 序列

序列用-空格來表示

yaml.load("""
- The Dagger
- The daager
- The Daaage
""")
['The Dagger', 'The daager', 'The Daaage']

序列可以巢狀:

yaml.load("""
-
    - HTML
    - LaTex
    - XML
    - VRML
    - YAML
-
    - BSD
    - GNU HURD
    - LINUX
""")
[['HTML', 'LaTex', 'XML', 'VRML', 'YAML'], ['BSD', 'GNU HURD', 'LINUX']]

也可不用另起一行來新建巢狀的序列:

yaml.load("""
- 1.1
- - 2.1
  - 2.2
- - - 3.1
    - 3.2
    - 3.3

""")
[1.1, [2.1, 2.2], [[3.1, 3.2, 3.3]]]

序列也可以巢狀到對映中:

yaml.load("""
left hand:
        - Ring of Tesla
        - Ring of King
right hand:
        - Ring of Asia
        - Ring of Cold
""")
{'left hand': ['Ring of Tesla', 'Ring of King'],
 'right hand': ['Ring of Asia', 'Ring of Cold']}
  • 對映

鍵值對用:空格來表示:

yaml.load("""
base armor: 0
base damaage: [4,4]
plus to: 16
multi:
    - test test
    - tets
""")
{'base armor': 0,
 'base damaage': [4, 4],
 'plus to': 16,
 'multi': ['test test', 'tets']}

複雜的鍵可以用?空格,比如字典的鍵如果是tuple型別,而序列是List,眾所周知,Python中字典的鍵只能是不可變的物件,所以需要將List 轉換為tuple.

yaml.load("""
? !!python/tuple [0,0] 
: The hero
""")
{(0, 0): 'The hero'}

對映也可以巢狀:

yaml.load("""
hero: 
    hp: 34
    sp: 9
orc:
    hp: 12
    sp: 34
""")
{'hero': {'hp': 34, 'sp': 9}, 'orc': {'hp': 12, 'sp': 34}}

對映也可以巢狀在序列中

yaml.load("""
- name: PyYAML
  status: 4
  langauage: python
- name: PYSYCK
  status: 5
  license: BSD
""")
[{'name': 'PyYAML', 'status': 4, 'langauage': 'python'},
 {'name': 'PYSYCK', 'status': 5, 'license': 'BSD'}]
  • 標量

有5種標量:純文字,單引號,雙一號,字面量,摺疊式

yaml.load("""
plain: Scroll of Remove Curse
single-quoted: 'Easy know'
double-quoted: "?"
literal:
     __              /.-.\
    /  )_____________\\  Y
   /_ /=== == === === =\ _\_
  ( /)=== == === === == Y   \
   `-------------------(  o  )
                        \___/
folded: >
 It removed all ordinary curses from all equipped items. # 注意開頭的空格
 Heavy or permanent curses are unaffected  

""")
{'plain': 'Scroll of Remove Curse',
 'single-quoted': 'Easy know',
 'double-quoted': '?',
 'literal': '__              /.-.    /  )_____________\\  Y /_ /=== == === === =\\ _\\_ ( /)=== == === === == Y      `-------------------(  o  ) \\___/',
 'folded': 'It removed all ordinary curses from all equipped items. # 注意開頭的空格 Heavy or permanent curses are unaffected  \n'}

載入YAML

import yaml

直接用yaml.load來載入一個不可信任的檔案是非常不安全的,yaml.loadpickle.load一樣強大,都可以呼叫任何Python函式。可以考慮用yaml.safe_load

yaml.load將一個YAML文件轉化為一個Python物件。

需要注意的是 '-' 與字串之間需要有空格,才表示一個列表。

a=yaml.load("""
 - Hesper
 - Pali
 - Apat
 - Epip
""")
a
['Hesper', 'Pali', 'Apat', 'Epip']
type(a)
list
yaml.load("""
 測試: 中文 
 age: 30
""") 
{'測試': '中文', 'age': 30}

需要重要的是 :與字串之間也有空格

  • 如果一個字串或者檔案包含多個文件,可以用yaml.load_all函式。
documents="""
---
name: first one
description: dkfsjk
---
name: johnyang
age: 29

---
- C
- C++
- C#
- B #
"""

注意多個文件之間用---分割。

yaml.load_all(documents)
<generator object load_all at 0x0000029B36EC2390>
for data in yaml.load_all(documents):
    print(data)
{'name': 'first one', 'description': 'dkfsjk'}
{'name': 'johnyang', 'age': 29}
['C', 'C++', 'C#', 'B']

空格 '#'是表示註釋

  • PyYAML允許構建任意型別的Python物件
yaml.load("""
none: [~,null]
bool: [ture,false,on,off]
int: 42
float: 3.14159
list: [LIST,RES]
dict: {hhp: 13,sps: dkf}
multiDict:
        dksk: fjsdk
        jfksd: eiw
""")
{'none': [None, None],
 'bool': ['ture', False, True, False],
 'int': 42,
 'float': 3.14159,
 'list': ['LIST', 'RES'],
 'dict': {'hhp': 13, 'sps': 'dkf'},
 'multiDict': {'dksk': 'fjsdk', 'jfksd': 'eiw'}}
  • 甚至Python 類例項可以用!!python/object來建立
class Hero:
    def __init__(self,name,hp,sp):
        self.name=name
        self.hp=hp
        self.sp=sp
    def __repr__(self):
        return "%s(name=%r,hp=%r,sp=%r)" %(self.__class__.__name__,self.name,self.hp,self.sp)
yaml.load("""
!!python/object:__main__.Hero  
name: jksdfk
hp: 1200
sp: 0

""")
Hero(name='jksdfk',hp=1200,sp=0)

注意 !!python/object:__main__.Hero中的:後面沒有空格!

匯出YAML

yaml.dump接受Python物件,匯出為一個YAML文件。

print(yaml.dump({'name':'johnyang','age':29,'hobby':['coding','reading','thinking']}))
age: 29
hobby: [coding, reading, thinking]
name: johnyang

yaml.dump接受第二個可選的引數,必須是開啟的文字/二進位制檔案,這種情況下,yaml.dump將會把產生的yaml文件寫入該文字,否則yaml.dump返回產生的文件。

stream=open('testYaml.yaml','w')
yaml.dump(data,stream)
print(yaml.dump(data))
{age: 29, name: johnyang}

print(yaml.dump([1,2,3],explicit_start=True))
--- [1, 2, 3]

print(yaml.dump(Hero('Gauss',hp=-3,sp=3)))
!!python/object:__main__.Hero {hp: -3, name: Gauss, sp: 3}

  • yaml.dump支援管控輸出格式的可選引數
print(yaml.dump(list(range(50))))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
  23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
  43, 44, 45, 46, 47, 48, 49]

print(yaml.dump(list(range(50)),width=50,indent=4))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
    28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
    40, 41, 42, 43, 44, 45, 46, 47, 48, 49]

print(yaml.dump(list(range(5)),canonical=True)) #canonical 意思是典型的;規範化
---
!!seq [
  !!int "0",
  !!int "1",
  !!int "2",
  !!int "3",
  !!int "4",
]

print(yaml.dump(list(range(5)),default_flow_style=False))
- 0
- 1
- 2
- 3
- 4

print(yaml.dump(list(range(5)),default_flow_style=True))
[0, 1, 2, 3, 4]

print(yaml.dump(list(range(5)),default_flow_style=True,default_style='""'))
[!!int "0", !!int "1", !!int "2", !!int "3", !!int "4"]