python的pyyaml模块详解(代码片段)

虫无涯 虫无涯     2022-11-04     234

关键词:

文章目录

注:原文链接

简介

Python的PyYAML模块是Python的YAML解析器和生成器。

安装

简单安装

pip install pyyaml

从源码安装

下载源码包PyYAML-3.13.tar.gz 并解压,在命令行下切换到解压后的包目录内并执行如下命令:

python setup.py install

如果想使用比纯Python版本更快的LibYAML绑定,需要先下载并安装LibYAML,然后在安装PyYAML的时候执行如下命令:

python setup.py --with-libyaml install

为了使用基于LibYAML的解析器和生成器,请使用 CParserCEmitter 类。例如:

from yaml import load, dump
try:
    from yaml import Cloader as Loader, CDumper as Dumper
except ImportError:
    from yaml import Loader, Dumper

# ...

data = load(stream, Loader=Loader)

# ...

output = dump(data, Dumper=Dumper)

请注意,基于纯Python和基于LibYAML的YAML解析器和生成器之间有一些细微但并不真正重要的区别。

最常被问到的问题

为什么如下所示的YAML文档在反序列化后再序列化,得到的YAML文档的格式与原来不一样?

import yaml
document = """
a: 1
b:
  c: 3
  d: 4
"""
print(yaml.dump(yaml.load(document)))

其中,上面代码的输出为:

a: 1
b: c: 3, d: 4

关于这个问题,其实,尽管最后得到的YAML文档的样式与原来的文档的样式不一致,但是却是正确的结果。

因为PyYAML默认会根据一个集合中是否有嵌套的集合来决定用哪种格式表示这个集合。如果一个集合中嵌套有其他集合,那么会使用块样式来表示,否则会使用流样式来表示。

如果想要集合总是以块样式表示,可以将 dump() 方法的 default_flow_style 参数值设为 False ,如下所示:

print(yaml.dump(yaml.load(document), default_flow_style=False))

上面代码的输出为:

a: 1
b:
  c: 3
  d: 4

使用详解

先导入 yaml 模块:

import yaml

加载YAML

警告:调用 yaml.load 处理从不可信任的源接收的数据可能存在风险。yaml.loadpickle.load 的功能一样强大,可以调用所有Python函数。

yaml.load 函数的作用是用来将YAML文档转化成Python对象。如下所示:

>>> yaml.load("""
... - Hesperiidae
... - Papilionidae
... - Apatelodidae
... - Epiplemidae
... """)
['Hesperiidae', 'Papilionidae', 'Apatelodidae', 'Epiplemidae']

yaml.load 函数可以接受一个表示YAML文档的字节字符串、Unicode字符串、打开的二进制文件对象或者打开的文本文件对象作为参数。若参数为字节字符串或文件,那么它们必须使用 utf-8utf-16 或者 utf-16-le 编码。yaml.load 会检查字节字符串或者文件对象的_BOM_(byte order mark)并依此来确定它们的编码格式。如果没有发现 BOM ,那么会假定他们使用 utf-8 格式的编码。

yaml.load 方法的返回值为一个Python对象,如下所示:

>>> yaml.load("'hello': ''")
'hello': '\\uf8ff'
>>> with open('document.yaml', 'w') as f:
...     f.writelines('- Python\\n- Ruby\\n- Java')
... 
>>> stream = open('document.yaml')
>>> yaml.load(stream)
['Python', 'Ruby', 'Java']

如果字符串或者文件中包含多个YAML文档,那么可以使用 yaml.load_all 函数将它们全部反序列化,得到的是一个包含所有反序列化后的YAML文档的生成器对象:

>>> documents = """
... name: bob
... age: 18
... ---
... name: alex
... age: 20
... ---
... name: jason
... age: 16
... """
>>> datas = yaml.load_all(documents)
>>> datas
<generator object load_all at 0x105682228>
>>> for data in datas:
...     print(data)
... 
'name': 'bob', 'age': 18
'name': 'alex', 'age': 20
'name': 'jason', 'age': 16

PyYAML允许用户构造任何类型的Python对象,如下所示:

>>> document = """
... none: [~, null]
... bool: [true, false, on, off]
... int: 55
... float: 3.1415926
... list: [Red, Blue, Green, Black]
... dict: name: bob, age: 18
... """
>>> yaml.load(document)
'none': [None, None], 'bool': [True, False, True, False], 'int': 55, 'float': 3.1415926, 'list': ['Red', 'Blue', 'Green', 'Black'], 'dict': 'name': 'bob', 'age': 18

即使是Python 类的实例,也可以使用标签 !!python/object 来进行构建,如下所示:

>>> class Person:
...     def __init__(self, name, age, gender):
...         self.name = name
...         self.age = age
...         self.gender = gender
...     def __repr__(self):
...         return f"self.__class__.__name__(name=self.name!r, age=self.age!r, gender=self.gender!r)"
... 
>>> yaml.load("""
... !!python/object:__main__.Person
... name: Bob
... age: 18
... gender: Male
... """)
Person(name='Bob', age=18, gender='Male')

注意,如果从不信任的源(例如互联网)接收一个YAML文档并由此构建一个任意的Python对象可能存在一定的风险。而使用 yaml.safe_load 方法能够将这个行为限制为仅构造简单的Python对象,如整数或者列表。

定义一个继承自yaml.YAMLObject 类的子类,然后将这个子类的类属性 yaml_loader 的值设置为 yaml.SafeLoader ,这样,这个类的对象就被标记为是安全的,从而可以被 yaml.safe_load 方法识别。不过有一点需要注意,在反序列化这样的Python对象时,只能使用 safe_loadsafe_load_all 方法。

转储YAML

yaml.dump 函数接受一个Python对象并生成一个YAML文档。

>>> import yaml
>>> emp_info =  'name': 'Lex',
... 'department': 'SQA',
... 'salary': 8000,
... 'annual leave entitlement': [5, 10]
... 
>>> print(yaml.dump(emp_info))
annual leave entitlement: [5, 10]
department: SQA
name: Lex
salary: 8000

yaml.dump 可以接受第二个可选参数,用于写入生成的YAML文本,这个参数的值可以是打开的文本或者二进制文件对象。如果不提供这个可选参数,则直接返回生成的YAML文档。

>>> with open('document.yaml', 'w') as f:
...     yaml.dump(emp_info, f)
... 
>>> import os
>>> os.system('cat document.yaml')
annual leave entitlement: [5, 10]
department: SQA
name: Lex
salary: 8000
0

如果要将多个Python对象序列化到一个YAML流中,可以使用 yaml.dump_all 函数。该函数接受一个Python的列表或者生成器对象作为第一个参数,表示要序列化的多个Python对象。

>>> obj = ['name': 'bob', 'age': 19, 'name': 20, 'age': 23, 'name': 'leo', 'age': 25]
>>> print(yaml.dump_all(obj))
age: 19, name: bob
--- age: 23, name: 20
--- age: 25, name: leo

你甚至可以序列化一个Python类的实例,如下所示:

>>> class Person:
...     def __init__(self, name, age, gender):
...         self.name = name
...         self.age = age
...         self.gender = gender
...     def __repr__(self):
...         return f"self.__class__.__name__(name=self.name!r, age=self.age!r, gender=self.gender!r)"
... 
>>> print(yaml.dump(Person('Lucy', 26, 'Female')))
!!python/object:__main__.Person age: 26, gender: Female, name: Lucy

yaml.dumpyaml.dump_all 方法还支持多个关键字参数,用来指定生成的YAML流中YAML文档的样式和是否包含其他信息。下面就来详细介绍下每个参数的含义和用法。

  • stream

    指定由于输出YAML流的打开的文件对象。默认值为 None,表示作为函数的返回值返回。

  • default_flow_style

    是否默认以流样式显示序列和映射。默认值为 None,表示对于不包含嵌套集合的YAML流使用流样式。设置为 True 时,序列和映射使用块样式。

  • default_style

    默认值为 None。表示标量不使用引号包裹。设置为 '"' 时,表示所有标量均以双引号包裹。设置为 "'" 时,表示所有标量以单引号包裹。

  • canonical

    是否以规范形式显示YAML文档。默认值为 None,表示以其他关键字参数设置的值进行格式化,而不使用规范形式。设置为 True 时,将以规范形式显示YAML文档中的内容。

  • indent

    表示缩进级别。默认值为 None, 表示使用默认的缩进级别(两个空格),可以设置为其他整数。

  • width

    表示每行的最大宽度。默认值为 None,表示使用默认的宽度80。

  • allow_unicode

    是否允许YAML流中出现unicode字符。默认值为 False,会对unicode字符进行转义。设置为 True 时,YAML文档中将正常显示unicode字符,不会进行转义。

  • line_break

    设置换行符。默认值为 None,表示换行符为 '',即空。可以设置为 \\n\\r\\r\\n

  • encoding

    使用指定的编码对YAML流进行编码,输出为字节字符串。默认值为 None,表示不进行编码,输出为一般字符串。

  • explicit_start

    每个YAML文档是否包含显式的指令结束标记。默认值为 None,表示流中只有一个YAML文档时不包含显式的指令结束标记。设置为 True 时,YAML流中的所有YAML文档都包含一个显式的指令结束标记。

  • explicit_end

    每个YAML文档是否包含显式的文档结束标记。默认值为 None,表示流中的YAML文档不包含显式的文档结束标记。设置为 True 时,YAML流中的所有YAML文档都包含一个显式的文档结束标记。

  • version

    用于在YAML文档中指定YAML的版本号,默认值为 None,表示不在YAML中当中指定版本号。可以设置为一个包含两个元素的元组或者列表,但是第一个元素必须为1,否则会引发异常。当前可用的YAML的版本号为1.0、1.1 和1.2。

  • tags

    用于指定YAML文档中要包含的标签。默认值为 None,表示不指定标签指令。可以设置为一个包含标签的字典,字典中的键值对对应各个不同的标签名和值。

>>> data = 'code': 200, 'status': 'success', 'message': [10, True, "Got it"]
>>> print(yaml.dump(data, version=(1, 2)))  # 设置YAML版本
%YAML 1.2
---
code: 200
message: [10, true, Got it]
status: success

>>> print(yaml.dump(data, version=(1, 2), tags='!name!': 'test'))  # 设置标签指令
%YAML 1.2
%TAG !name! test
---
code: 200
message: [10, true, Got it]
status: success

>>> print(yaml.dump(data,  # 设置使用块样式
...                 version=(1, 2),
...                 tags='!name!': 'test',
...                 default_flow_style=False))
%YAML 1.2
%TAG !name! test
---
code: 200
message:
- 10
- true
- Got it
status: success

>>> print(yaml.dump(data,  # 设置标量使用单引号包裹
...                 version=(1, 2),
...                 tags='!name!': 'test',
...                 default_flow_style=False,
...                 default_style="'"))
%YAML 1.2
%TAG !name! test
---
'code': !!int '200'
'message':
- !!int '10'
- !!bool 'true'
- 'Got it'
'status': 'success'

>>> print(yaml.dump(data,  # 设置标量使用双引号包裹 
...                 version=(1, 2),
...                 tags='!name!': 'test',
...                 default_flow_style=False,
...                 default_style='"'))
%YAML 1.2
%TAG !name! test
---
"code": !!int "200"
"message":
- !!int "10"
- !!bool "true"
- "Got it"
"status": "success"

>>> print(yaml.dump(data,  # 设置YAML文档包含显式的指令结束标记和文档结束标记
...                 explicit_start=True,
...                 explicit_end=True))
---
code: 200
message: [10, true, Got it]
status: success
...

>>> print(yaml.dump(data, canonical=True))  # 设置文档使用规范形式
---
!!map 
  ? !!str "code"
  : !!int "200",
  ? !!str "message"
  : !!seq [
    !!int "10",
    !!bool "true",
    !!str "Got it",
  ],
  ? !!str "status"
  : !!str "success",


>>> print(yaml.dump(data, encoding='utf-8'))  # 将YAML流使用utf-8格式进行编码
b'code: 200\\nmessage: [10, true, Got it]\\nstatus: success\\n'
>>> user_info = 'name': '张学友', 'age': 57, '外号': ['歌神', '乌蝇哥']
>>> print(yaml.dump(user_info))  # 若不设置 allow_unicode 参数,则unicode字符会转义
age: 57
name: "\\u5F20\\u5B66\\u53CB"
"\\u5916\\u53F7": ["\\u6B4C\\u795E", "\\u4E4C\\u8747\\u54E5"]
  
>>> print(yaml.dump(user_info, allow_unicode=True))  # 设置允许包含unicode字符
age: 57
name: 张学友
外号: [歌神, 乌蝇哥]


构造、表示和解析

可以定义自己的特定于应用程序的标记。最简单的方法是定义 yaml.YAMLObject 的子类,如下所示:

>>> class Person(yaml.YAMLObject):
...     yaml_tag = '!Person'
...     def __init__(self, name, age, gender):
...         self.name = name
...         self.age = age
...         self.gender = gender
...     def __repr__(self):
...         return f"self.__class__.__name__(name=self.name!r, age=self.age!r, gender=self.gender!r)"
... 

如上的定义已经足够自动化反序列化和序列化 Person 对象:

>>> text = """
... --- !Person
... name: Bob
... age: 22
... gender: Male
... """
>>> yaml.load(text)
Person(name='Bob', age=22, gender='Male')
>>> print(yaml.dump(Person('Bob', 22, 'Male')))
!Person age: 22, gender: Male, name: Bob

yaml.YAMLObject 使用元类魔法注册了一个用来将YAML节点转换为类实例的 constructors 和用来将YAML节点反序列化为Python类实例的表示器 representers

如果你不想使用元类,你可以使用 yaml.add_constructoryaml.add_representer 来注册你的 constructorsrepresenters。如下所示:

>>> class Dice(tuple):
...     def __new__(cls, a, b):
...         return tuple.__new__(cls, [a, b])
...     def __repr__(self):
...         return 'Dice(%s, %s)' % self
... 
>>> print(Dice(3集中化管理平台ansible详解(代码片段)

...置管理、应用部署、执行特定任务的开源平台.它是基于python语言,由Paramiko和PyYAML两个关键模块构建。集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能... 查看详情

python之ruamel.yaml模块详解(代码片段)

Python之ruamel.yaml模块详解(一)1ruamel.yaml简介2ruamel.yaml安装2.1setuptools安装2.2pip安装ruamel.yaml2.3处理jinja2/YAML模板2.4yaml命令行实用程序3yaml.load()和yaml.dump()解析3.1yaml.load()读ymal文件3.2yaml.dump()写ymal文件3.3基于C的SafeLoader3.4基... 查看详情

python的内置模块详解(代码片段)

一、什么是模块  模块就是封装了一些列功能的py文件,我们使用的时候直接导入这个文件,通过传入参数的方式使用其他文件的功能函数二、模块有哪些内置模块自定义模块第三方模块三、如何导入模块  导入模块分为4种... 查看详情

python-模块详解(代码片段)

模块:模块的分类:第三方模块/扩展模块:没在安装python解释器的时候安装的那些功能自定义模块:你写的功能如果是一个通用的功能,那你就把它当做一个模块内置模块:安装python解释器的时候跟着装上的那些方法什么是模块:有的功... 查看详情

python操作yaml的方法详解(代码片段)

这篇文章主要为大家介绍了python操作yaml的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助一、参考链接https://pyyaml.org/wiki/PyYAMLDocumentation二、python类型转换为yaml`#-*-coding:utf-8-*-... 查看详情

python——pickle模块的详解(代码片段)

pickle模块详解该pickle模块实现了用于序列化和反序列化Python对象结构的二进制协议。 “Pickling”是将Python对象层次结构转换为字节流的过程, “unpickling”是反向操作,从而将字节流(来自二进制文件或类似... 查看详情

python里面的xlrd模块详解(代码片段)

...用xlrd模块?3.怎样使用xlrd模块?1.什么是xlrd模块?  ?python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库。今天就先来说一下xlrd模块:一、安装xlrd模块  ?到python官网下载http://pypi.python.org/pypi/xlrd模块... 查看详情

python标准库datetime之date模块详解(代码片段)

Python标准库datetime之date模块详解datetime是Python提供的操作日期和时间的标准库,主要有datetime.date模块、datetime.time模块及datetime.datetime模块。其中date模块提供了日期操作相关的方法;time模块提供了时间操作相关的方法;datetime提... 查看详情

python模块详解及import本质(代码片段)

...在当前目录下的模块和包导入模块定义本质就是.py结尾的python文件.用来从逻辑上组织python代码(变量,函数,类,逻辑)文件名:test.py; 对应的模块名:test 模块导入方式importmodule_name调用时需要加module_name.(有点类似java中的类名.... 查看详情

模块详解(代码片段)

...1.内置模块2.第三方模块3.自定义模块模块的格式:1.使用python编写的.py文件2.已被编译成共享库或DLL的C或C++扩展3.把一系列模块组织到一起的文件夹(注:文件夹下有一个---init---.py的文件,该文件称之为包)4.使用C编写并链接到p... 查看详情

python3--os模块详解(代码片段)

Python3之OS模块详解:os.sep:取代操作系统特定的路径分隔符os.name:指示你正在使用的工作平台。比如对于Windows,它是‘nt‘,而对于Linux/Unix用户,它是‘posix‘。os.getcwd:得到当前工作目录,即当前python脚本工作的目录路径。os.geten... 查看详情

python获取系统信息模块详解(代码片段)

python是跨平台语言,有时候我们的程序需要运行在不同系统上,例如:linux、MacOs、Windows,为了使程序有更好通用性,需要根据不同系统使用不同操作方式。我们可以使用platform模块来获取系统信息。platform是python自带模块,我们... 查看详情

详解python模块化——模块(modules)和包(packages)(代码片段)

文章目录引言PythonModules模块导入模块①导入整个模块②导入模块中的特定函数③导入模块中的所有函数给导入的模块一个别名单独运行模块加速模块加载PythonPackages包引用包(Package)中的模块引用包(Package)中... 查看详情

python标准库datetime之time模块详解(代码片段)

Python标准库datetime之time模块详解上一篇博文中我们学习了datetime库中的日期模块(date),本文我们来学习下时间模块(time)。传送门:点击即可跳转日期模块1、时间对象类主要处理时、分、秒操作创建对象常用的参数有(小时,分钟,秒... 查看详情

python基础学习第九节import用法详解(代码片段)

Python基础学习之import用法1.直接引入模块;import模块名;import模块名,这时python可以引入以下两种模块;举例如下:我们安装好的模块;(其实就是在环境变量路径下的模块;)运行文件所在目录下的文件;(这里我们推荐用from... 查看详情

saltstack详解+部署apache服务(代码片段)

saltstack介绍1、saltstack是使用python语言开发的;2、轻量级的管理工具,批量执行命令;3、常用模块:pkg(包)、file(文件)、cmd(执行命令或脚本)、user、service、cron4、saltstack数据系统Grains(静态数据)pillar(动态数据)saltsta... 查看详情

python之configparser模块详解和使用(代码片段)

...安装pip3installconfigparser2configparser简介用来读取配置文件的python包;一般做自动化测试的时候,会使用到这个模块,用来封装一些常量。比如数据库、邮件、用户名密码、项目常量等等;这个使用根据个人喜好和项目来确定,不一... 查看详情

python模块导入详解(代码片段)

定义模块:用来从逻辑上组织Python代码(变量、函数、类、逻辑)去实现一个功能。本质就是.py结尾的Python文件。包:用来从逻辑上组织模块的(可以放一堆模块在目录下)。本质就是一个目录(必须带有一个__init__.py文件)。 导... 查看详情