当前位置: 首页 > 工具软件 > PyYAML > 使用案例 >

PyYaml基本操作

李新霁
2023-12-01

1. PyYaml

PyYaml是Python的一个专门针对yaml文件操作的模块,使用起来非常简单

pip install PyYaml

基本格式要求

1,YAML大小写敏感;
2,使用缩进代表层级关系;
3,缩进只能使用空格,不能使用TAB,不要求空格个数,只需要相同层级左对齐(一般2个或4个空格)
4、缩进的空格数目不重要,只要相同层级的元素左对齐即可
5、# 表示注释,从它开始到行尾都被忽略

1、对象

key: 
    child-key: value
    child-key2: value2

转化为

key: {child-key: value, child-key2: value2}

2、数组

-
    - 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}]

3、常量

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连接,最后使用+代表时区

一些特殊符号

1. 分段

在同一个yaml文件中,可以用 — 来分段,这样可以将多个文档写在一个文件中
… 和—配合使用,在一个配置文件中代表一个文件的结束:

---
name: James
age: 20
---
name: Lily
age: 19

这时候我们就得用到我们的 load_all() 方法出场了,load_all() 方法会生成一个迭代器,可以用for输出出来

2. 强制转换

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去掉

3、单双引号

单引号和双引号的区别,单引号中的特殊字符转到Python会被转义,也就是到最后是原样输出了,双引号不会被Python转义,到最后是输出了特殊字符

4、换行处理

字符串处理中写成多行、’|’、’>’、’+’、’-‘的意义这里就不讲了
>在字符串中折叠换行,| 保留换行符,这两个符号是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'}

5. 引用

&* 用于引用

name: &name 灰蓝
tester: *name
{'name': u'\u7070\u84dd', 'tester': u'\u7070\u84dd'}

6,合并内容

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}

有了合并,我们就可以在配置中,把相同的基础配置抽取出来,在不同的子配置中合并引用即可

7、PyYaml使用

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转化为python类型

yaml.dump()
yaml.dump_all()
yaml.safe_dump()
yaml.safe_dump_all()

这四个方法把python文件转化为str

8、 构造器(constructors)、表示器(representers)、解析器(resolvers )

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)

2. yaml.add_constructoryaml.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,其他的不示例讲解了。

3. add_implicit_resolver

如果你不想每次都写标签,也可以用 add_implicit_resolver 方法添加解析器,然后它就能够把指定样式的没有标签的基本元素解析成对应的Python对象。这个就不详细分析给示例了。感兴趣的同学自己看文档学习吧。

9. 结语

yaml是一种很清晰、简洁的格式,而且跟Python非常合拍,非常容易操作,我们在搭建自动化测试框架的时候,可以采用yaml作为配置文件,或者用例文件,下面给出一个用例的示例,这个示例来自于Python restful接口框架 pyresttest:

 类似资料: