首页 > 技术文章 > python基础[18]——pyyaml常用方法,构造器、表示器、解析器

saiminhou 2020-09-25 11:38 原文

可以先查看这个文章,了解yaml的基本情况:https://www.cnblogs.com/saiminhou/p/13729910.html
可以先查看这个文章,了解python文件处理:https://www.cnblogs.com/saiminhou/p/13729160.html

  1. 在python里面,需要命令下载ymal模块:
pip install pyyaml
  1. 常用函数说明
data = load(stream, Loader=yaml.FullLoader)
output = dump(data, Dumper=Dumper)

yaml.load():读取yaml文件,返回一个对象
yaml.load_all()生成一个迭代器
yaml.dump():把python对象转换成yaml格式
yaml.dump_all()接受列表或生成器生成,输出到一个文件中
import yaml
fpath = 'test.yaml'
try:
    f = open(fpath, 'r')
    # y = yaml.load(f)#这样会有警告,as the default Loader is unsafe.
    y = yaml.load(f, Loader=yaml.FullLoader)  # 警告解除
    print(y)
except IOError:
    print('文件不存在或无法打开')
finally:
    if f:
        f.close()
aproject = {'name': 'Silenthand Olleander',
            'race': 'Human',
            'traits': ['ONE_HAND', 'ONE_EYE']
            }
with open(fpath,"w") as f:
    yaml.dump(aproject, f)
    print(yaml.dump(aproject))
name: Silenthand Olleander
race: Human
traits:
- ONE_HAND
- ONE_EYE
obj1 = {"name": "James", "age": 20}
obj2 = ["Lily", 19]

with open(fpath, 'w') as f:
    yaml.dump_all([obj1, obj2], f)
age: 20
name: James
---
- Lily
- 19

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

yaml.YAMLObject可以定义自己的特定于应用程序的标签。使用元类Monster来注册一个构造函数和一个表示程序

#自定义一个Monster的类
class Monster(yaml.YAMLObject):
    yaml_tag = r'!person'
    def __init__(self, name, hp,ac,attacks):#构造器,将一个YAML节点转换为一个类实例
        self.name = name
        self.hp = hp
        self.ac = ac
        self.attacks = attacks

    def __repr__(self):#表示器,将一个类实例序列化为一个YAML节点。
        return "%s(name=%r, hp=%r, ac=%r, attacks=%r)" % (
            self.__class__.__name__, self.name, self.hp, self.ac, self.attacks)

上面的定义足以自动load和dumpMonster对象:

print(yaml.load("""
---!Monster
name:Cave spider
hp:[2,6]
ac:126
attacks:[BITE,HURT]
""",Loader=yaml.FullLoader))#需要注意---

 print(yaml.dump(Monster(name='Cave spider',hp=[2,6],ac=126,attacks=['BITE','HURT'])))   

输出的结果为:

---!Monster name:Cave spider hp:[2,6] ac:126 attacks:[BITE,HURT]
!Monster
ac: 126
attacks:
- BITE
- HURT
hp:
- 2
- 6
name: Cave spider

如果您不想使用元类,则可以使用函数yaml.add_constructor和来注册构造函数和表示形式yaml.add_representer

例如,当不使用函数yaml.add_constructor,为以下Dice类添加构造函数和表示形式

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,6)
print(yaml.dump(Dice(3,6)))

输出的结果为:

Dice(3,6)
!!python/object/new:__main__.Dice
- !!python/tuple
  - 3
  - 6

假设要在YAML中Dice表示一个对象AdB,可以使用函数yaml.add_constructor

print yaml.dump(Dice(3,6))
#3d6
  1. 定义一个表示器,将带有标签的dice对象转换为标量节点!dice,然后进行注册。
def dice_representer(dumper, data):
    return dumper.represent_scalar(u'!dice', u'%sd%s' % data)
yaml.add_representer(Dice, dice_representer)
print(yaml.dump({'gold': Dice(10,6)}))#还可以dump`Dice`对象的实例:
#{gold: !dice '10d6'}
  1. 定义一个print(yaml.load("!dice 8d4",Loader=yaml.FullLoader))#load一个Dice对象
def dice_constructor(loader, node):
    value = loader.construct_scalar(node)
    a, b = map(int, value.split('d'))
    return Dice(a, b)

yaml.add_constructor(u'!dice', dice_constructor)#添加代码来构造一个Dice对象
print(yaml.load("""
initial hit points: !dice 8d4
""",Loader=yaml.FullLoader))#load一个`Dice`对象
#{'initial hit points': Dice(8,4)}

您可能不想在任何地方都指定!dice标签,让看起来像XdY的未加标签的纯标量都具有隐式标签!dice

使用add_implicit_resolver

import re
pattern = re.compile(r'^\d+d\d+$')
yaml.add_implicit_resolver(u'!dice', pattern)

现在,您无需指定标签来定义Dice对象:

print yaml.dump({'treasure': Dice(10,20)})
print(yaml.load("!dice 8d4",Loader=yaml.FullLoader))#load一个`Dice`对象
print(yaml.load("damage: 5d10",Loader=yaml.FullLoader))
#treasure: 10d20
#Dice(8,4)
#{'damage': Dice(5,10)}

推荐阅读