!Employee old:
id: some_id
name: John
cfg:
param: "abc"
我需要加载更新,并保存一个yaml文件,其中包含与上面类似的结构。
我尝试使用add_constructor和add_representer。当标签单独放置时,这有效。
!Employee
old:
id: some_id
name: John
cfg:
param: "abc"
不过我想避免对原始文件进行预处理。我也没有鲁梅尔(在其他帖子上建议)。
在下面的示例中,yaml 没有看到扫描整个结构,即不包括标签下的映射部分。
#================================================== ====================
import yaml
# Custom class to handle !Employee old: name: Peter
class Employee:
def __init__(self, status, data=None):
self.status = status # e.g., "old"
self.data = data or {} # e.g., {'name': 'Peter'}
def __repr__(self):
return f"!Employee {self.status}: {self.data}"
# Custom constructor for the !Employee tag
def employee_constructor(loader, node):
# Check if the node is a MappingNode
print(f"EMPL_CONST node: {node}")
if isinstance(node, yaml.MappingNode):
# Expecting only one key-value pair (e.g., "old": {"name": "Peter"})
print(f"EMPL_CONST node: {node.value[0]}")
first_key_node, value_node = node.value[0]
# The key is the scalar "old"
status = loader.construct_scalar(first_key_node)
# The value is the mapping part {"name": "Peter"}
data = loader.construct_mapping(value_node)
# Return an Employee object with the status and data
return Employee(status, data)
raise yaml.constructor.ConstructorError(None, None, f"Unexpected node type: {type(node)}", node.start_mark)
# Custom representer for the !Employee tag
def employee_representer(dumper, data):
# Create a tag with the status (e.g., !Employee old)
tag = f"!Employee"
return dumper.represent_mapping(tag, {data.status: data.data})
# Register the custom constructor and representer
yaml.add_constructor('!Employee', employee_constructor)
yaml.add_representer(Employee, employee_representer)
def load_yaml(file_path):
with open(file_path, 'r') as file:
data = yaml.load(file, Loader=yaml.FullLoader)
# print(data)
return data
def save_yaml(file_path, data):
with open(file_path, 'w') as file:
yaml.dump(data, file, default_flow_style=False)
# Testing the code
if __name__ == "__main__":
yaml_string = """
!Employee old:
name: Some_Name
id: some_id
cfg:
param : 'abc'
"""
# Load the YAML data`your text`
data = yaml.load(yaml_string, Loader=yaml.FullLoader)
# data = load_yaml("input3.yaml")
print("Loaded YAML data:")
print(data)
# Modify the data (optional)
data['cfg']['param'] = 'xyz'
# Dump the data back to YAML format
output = yaml.dump(data, default_flow_style=False)
print("\nModified YAML output:")
print(output)
save_yaml("output3.yaml", data)
您使用了错误的库来执行这种往返(加载/修改/保存)操作。 使用 PyYAML,除了必须编写自定义加载程序和转储程序之外,您还将丢失引用、注释。 另外 PyYAML 只能处理 YAML 1.1 的一个子集,该子集已于 15 年前被取代。
我建议您尝试 ruamel.yaml (双关语:我是该包的作者):
import sys
import ruamel.yaml
yaml_str = """\
!Employee old:
[42, 13]: some_id
name: John # this stays the same
cfg:
param: "abc" # this has to change
"""
yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4)
yaml.preserve_quotes = True
data = yaml.load(yaml_str)
data['cfg']['param'] = 'xyz'
yaml.dump(data, sys.stdout)
给出:
!Employee old:
[42, 13]: some_id
name: John # this stays the same
cfg:
param: "xyz" # this has to change