PyYaml是Python的一个专门针对yaml文件操作的模块,使用起来非常简单
pip install PyYaml
1,YAML大小写敏感;
2,使用缩进代表层级关系;
3,缩进只能使用空格,不能使用TAB,不要求空格个数,只需要相同层级左对齐(一般2个或4个空格)
4、缩进的空格数目不重要,只要相同层级的元素左对齐即可
5、# 表示注释,从它开始到行尾都被忽略
key:
child-key: value
child-key2: value2
转化为
key: {child-key: value, child-key2: value2}
-
- Java
- LOL
[[Java,LOL]]
companies:
-
id: 1
name: company1
price: 200W
-
id: 2
name: company2
price: 500W
companies: [{id: 1,name: company1,price: 200W},{id: 2,name: company2,price: 500W}]
YAML中提供了多种常量结构,包括:整数,浮点数,字符串,NULL,日期,布尔,时间。下面使用一个例子来快速了解常量的基本使用
boolean:
- TRUE #true,True都可以
- FALSE #false,False都可以
float:
- 3.14
- 6.8523015e+5 #可以使用科学计数法
int:
- 123
- 0b1010_0111_0100_1010_1110 #二进制表示
null:
nodeName: 'node'
parent: ~ #使用~表示null
string:
- 哈哈
- 'Hello world' #可以使用双引号或者单引号包裹特殊字符
- newline
newline2 #字符串可以拆成多行,每一行会被转化成一个空格
date:
- 2018-02-17 #日期必须使用ISO 8601格式,即yyyy-MM-dd
datetime:
- 2018-02-17T15:02:31+08:00 #时间使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区
在同一个yaml文件中,可以用 — 来分段,这样可以将多个文档写在一个文件中
… 和—配合使用,在一个配置文件中代表一个文件的结束:
---
name: James
age: 20
---
name: Lily
age: 19
这时候我们就得用到我们的 load_all()
方法出场了,load_all()
方法会生成一个迭代器,可以用for输出出来
yaml是可以进行强制转换的,用 !!
实现,如下:
string:
- !!str 54321
- !!str true
相当于把数字和布尔类型强转为字符串。当然允许转型的类型很多,比如
--- !!set
- Mark McGwire: 65
- Sammy Sosa: 63
- Sammy Sosa: 63
- Ken Griffy: 58
将数组解析为set,简单理解,转化的内容就是:[{Ken Griffy=58}, {Mark McGwire=65}, {Sammy Sosa=63}]
,重复的Sammy Sosa去掉
单引号和双引号的区别,单引号中的特殊字符转到Python会被转义,也就是到最后是原样输出了,双引号不会被Python转义,到最后是输出了特殊字符
字符串处理中写成多行、’|’、’>’、’+’、’-‘的意义这里就不讲了
>在字符串中折叠换行,| 保留换行符,这两个符号是YAML中字符串经常使用的符号
accomplishment: >
Mark set a major league
home run record in 1998.
stats: |
65 Home Runs
0.278 Batting Average
{'accomplishment': 'Mark set a major league home run record in 1998.\n', 'stats': '65 Home Runs\n0.278 Batting Average\n'}
&
和 *
用于引用
name: &name 灰蓝
tester: *name
{'name': u'\u7070\u84dd', 'tester': u'\u7070\u84dd'}
merge:
- &CENTER { x: 1, y: 2 }
- &LEFT { x: 0, y: 2 }
- &BIG { r: 10 }
- &SMALL { r: 1 }
sample1:
<<: *CENTER
r: 10
sample2:
<< : [ *CENTER, *BIG ]
other: haha
sample3:
<< : [ *CENTER, *BIG ]
r: 100
sample1
中,<<: *CENTER意思是引用{x: 1,y: 2},并且合并到sample1中,那么合并的结果为:sample1={r=10, y=2, x=1}
sample2
中,<<: [*CENTER, *BIG] 意思是联合引用{x: 1,y: 2}和{r: 10},并且合并到sample2中,那么合并的结果为:sample2={other=haha, x=1, y=2, r=10}
sample3
中,引入了*CENTER, *BIG,还使用了r: 100覆盖了引入的r: 10,所以sample3值为:sample3={r=100, y=2, x=1}
有了合并,我们就可以在配置中,把相同的基础配置抽取出来,在不同的子配置中合并引用即可
5.1之后的发现yaml.load(input)弃用了
yaml 5.1之后的使用方式有两种:
方法一
1 def operateYaml(self,filename):
2 file = open(filename, "r",encoding='utf-8')
3 data = yaml.load(file,Loader=yaml.FullLoader) #loader可选择BaseLoader、SafeLoader、FullLoader、UnsafeLoader
4 file.close()
5 return data
BaseLoader
:仅加载最基本的YAML
SafeLoader
:安全地加载YAML语言的子集。建议用于加载不受信任的输入。(safe_load)
FullLoader
:加载完整的YAML语言。避免任意代码执行。这是当前(PyYAML 5.1)默认加载器调用yaml.load(input)(发出警告后)(full_load)
UnsafeLoader
(也称为Loader向后兼容性):原始的Loader代码,可以通过不受信任的数据输入轻松利用。(unsafe_load)
方法二
1 def operateYaml(self,filename):
2 file = open(filename, "r",encoding='utf-8')
3 data = yaml.full_load(file) #可使用3种不同的加载方式:yaml.safe_load、yaml.full_load、yaml.unsafe_load
4 file.close()
5 return data
yaml.safe_load
yaml.full_load
yaml.unsafe_load
yaml.dump()
yaml.dump_all()
yaml.safe_dump()
yaml.safe_dump_all()
1.yaml.YAMLObject
yaml.YAMLObject用元类来注册一个构造器(也就是代码里的 __init__()
方法),让你把yaml节点转为Python对象实例,用表示器(也就是代码里的 __repr__()
函数)来让你把Python对象转为yaml节点,看代码:
# -*- coding: utf-8 -*-
import yaml
class Person(yaml.YAMLObject):
yaml_tag = '!person'
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return '%s(name=%s, age=%d)' % (self.__class__.__name__, self.name, self.age)
james = Person('James', 20)
print yaml.dump(james) # Python对象实例转为yaml
lily = yaml.load('!person {name: Lily, age: 19}')
print lily # yaml转为Python对象实例
!person {age: 20, name: James}
Person(name=Lily, age=19)
yaml.add_constructor
和 yaml.add_representer
你可能在使用过程中并不想通过上面这种元类的方式,而是想定义正常的类,那么,可以用这两种方法
# -*- coding: utf-8 -*-
import yaml
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return 'Person(%s, %s)' % (self.name, self.age)
james = Person('James', 20)
print yaml.dump(james) # 没加表示器之前
def person_repr(dumper, data):
return dumper.represent_mapping(u'!person', {"name": data.name, "age": data.age}) # mapping表示器,用于dict
yaml.add_representer(Person, person_repr) # 用add_representer方法为对象添加表示器
print yaml.dump(james) # 加了表示器之后
def person_cons(loader, node):
value = loader.construct_mapping(node) # mapping构造器,用于dict
name = value['name']
age = value['age']
return Person(name, age)
yaml.add_constructor(u'!person', person_cons) # 用add_constructor方法为指定yaml标签添加构造器
lily = yaml.load('!person {name: Lily, age: 19}')
print lily
!!python/object:__main__.Person {age: 20, name: James}
!person {age: 20, name: James}
Person(Lily, 19)
第一行是没加表示器之前,多丑!中间那行是加了表示器之后,变成了规范的格式,下面添加了构造器,能够把 !person 标签转化为Person对象。
这里用了 construct_mapping ,还有其他好多 construct_document, construct_object,construct_scalar,construct_sequence,construct_pairs,具体怎么用,可以自己研究下,看看API,看看源码学习下。
对应的 representer 也一样,有很多,这里只用了 represent_mapping,其他的不示例讲解了。
如果你不想每次都写标签,也可以用 add_implicit_resolver 方法添加解析器,然后它就能够把指定样式的没有标签的基本元素解析成对应的Python对象。这个就不详细分析给示例了。感兴趣的同学自己看文档学习吧。
yaml是一种很清晰、简洁的格式,而且跟Python非常合拍,非常容易操作,我们在搭建自动化测试框架的时候,可以采用yaml作为配置文件,或者用例文件,下面给出一个用例的示例,这个示例来自于Python restful接口框架 pyresttest: