Python 读写和解析 YAML 文件格式

目标

  • 读写API简单
  • 解析出来的数据结构易处理
  • 支持对象的序列化/反序列化

一个比较好用的库是ruamel,需要安装一下:

pip install ruamel.yaml

然后代码中导入即可:

from ruamel.yaml import YAML

但导入的YAML是个类,真正用的时候,需要创建一个实例
yaml = YAML()

读写文件

准备一个配置文件:

id: 100
name: "测试项目"
version: "3.1"
steps:
  - id: 18
    action: "Prepare"
    expects:
      - id: 238,
        result: GOOD
      - id: 239,
        result: PERFECT

代码中首先需要自行打开文件,然后把文件对象传给yaml实例:

        with open(conf_file) as f:
            data = yaml.load(f)
            for k, v in data.items():
                cls.handle_value(data, k, v)
        conf = yaml.load(f)

这里遍历load后的结果,然后通过业务函数(handle_value)自行处理的。

写和读的代码类似,还是自行用写模式打开文件,然后把一个dict/list嵌套结构的对象,传给dump函数即可

        with open(conf_file, 'w') as f:
            the_list = []
            for step in self.steps:
                the_list.append(step.to_dict())
            documents = yaml.dump(the_list, f)

例子里最外层对象是list,替换成dict也没有问题,总之需要是可枚举内容的对象。

序列化/反序列化

ruamel本身提供序列化/反序列化支持:

  • 首先,给需要序列化的类,加上yaml_object注解
  • 添加一个yaml_tag类属性,作为序列化前缀
  • 给这个类添加to_yaml和from_yaml两个类方法,分别处理序列化,和反序列化

示例如下:

@yaml_object(yaml)
class ScreenRect(dict):
    yaml_tag = u'!rect'

    def __init__(self, left: int = None, right: int = None, top: int = None, bottom: int = None):
        # super(ScreenRect, self).__init__([left, right, top, bottom])
        # self._inner_list = [left, right, top, bottom]
        self['l'] = left
        self['r'] = right
        self['t'] = top
        self['b'] = bottom

    @property
    def left(self):
        return self['l']

    @property
    def right(self):
        return self['r']

    @property
    def top(self):
        return self['t']

    @property
    def bottom(self):
        return self['b']

    def __str__(self):
        return 'l:{},  r:{},  t:{},  b:{}'.format(self.left, self.right, self.top, self.bottom)

    @classmethod
    def to_yaml(cls, representer, node):
        return representer.represent_scalar(cls.yaml_tag,
                                            'l:{}, r:{}, t:{}, b:{}'.format(node.left, node.right, node.top,
                                                                            node.bottom))
        # return {'l': self.left, 'r': self.right, 't': self.top, 'b': self.bottom}

    @classmethod
    def from_yaml(cls, constructor, node):
        splits = node.value.split(', ')
        # test = list(map(lambda x: x + '_sss', splits))
        v = list(map(lambda x: x[1], map(methodcaller("split", ":"), splits)))
        # print(v)
        return cls(left=int(v[0]), right=int(v[1]), top=int(v[2]), bottom=int(v[3]))

上例中,ScreenRect类是dict子类,但希望序列化的时候,按特定格式生成字符串,所以在to_yaml中做了包装,几个property的定义只是为了以后ScreenRect类实例方便读写数据,并不是必须的。生成以后的数据,类似下面这个样子:

rect: !rect l:1415, r:1805, t:239, b:609

中文字符

一开始使用的时候,发现utf-8编码的配置文件无法被读取,还以为ruamel不支持,后来发现是自己代码的问题,只需要打开文件的时候,指定编码就可以了:

with open(conf_file, encoding='utf-8') as f:

hawk
关注创业公司的技术与团队
286 声望
18 粉丝
0 条评论
推荐阅读
从 chatgpt 大火预测近未来
ChatGPT 有望再次统一互联网的入口,使得由 APP 建立的独立信息帝国逐渐崩溃。这将改变人们对信息的获取方式,让我们能够获得更快、更准确的信息。

songofhawk1阅读 566

封面图
数据结构与算法:二分查找
一、常见数据结构简单数据结构(必须理解和掌握)有序数据结构:栈、队列、链表。有序数据结构省空间(储存空间小)无序数据结构:集合、字典、散列表,无序数据结构省时间(读取时间快)复杂数据结构树、 堆图二...

白鲸鱼9阅读 5.2k

滚蛋吧,正则表达式!
你是不是也有这样的操作,比如你需要使用「电子邮箱正则表达式」,首先想到的就是直接百度上搜索一个,然后采用 CV 大法神奇地接入到你的代码中?

良许3阅读 1.4k

搭个ChatGPT算法模型,从哪开始?
最近 ChatGPT 很火,火到了各行各业。记得去年更多的还是码农最新体验后拿它搜代码,现在各行各业都进来体验,问它咋理财、怎么写报告和给小孩起名。😂 也因此让小傅哥在头条的一篇关于 ChatGPT 的文章都有了26万...

小傅哥6阅读 1.1k

封面图
程序员适合创业吗?
大家好,我是良许。从去年 12 月开始,我已经在视频号、抖音等主流视频平台上连续更新视频到现在,并得到了不错的评价。每个视频都花了很多时间精力用心制作,欢迎大家关注哦~考虑到有些小伙伴没有看过我的视频,...

良许3阅读 1.2k

Ubuntu20.04 从源代码编译安装 python3.10
Ubuntu 22.04 Release DateUbuntu 22.04 Jammy Jellyfish is scheduled for release on April 21, 2022If you’re ready to use Ubuntu 22.04 Jammy Jellyfish, you can either upgrade your current Ubuntu syste...

ponponon1阅读 4.5k评论 1

Python实现Windows弹出微信消息通知(可显示发送人和消息内容)
Mac微信是有一个消息通知的,这一点就挺好的,有时候根本不用点开开看就能看到消息内容。而Windows电脑版是没有这个消息通知的,只有右下角图标闪烁。

TANKING3阅读 3.7k评论 1

封面图
286 声望
18 粉丝
宣传栏