【问题标题】:Conditionally dumping an attribute using pyyaml/ruamel.yaml使用 pyyaml/ruamel.yaml 有条件地转储属性
【发布时间】:2021-01-10 07:29:47
【问题描述】:

我有一个类似这样的 Python 类:

from dataclasses import dataclass
from ruamel.yaml import yaml_object, YAML

yaml = YAML()

@yaml_object(yaml)
@dataclass
class DataObject:
    normal_attr: str
    normal_attr_2: str
    conditional_attr: str

然后我希望能够根据某些条件使用ruamel.yaml(基于 PyYaml)有条件地转储conditional_attr。理想情况下,它会像这样工作:

data = DataObject()

if verbose_output:
    yaml.dump(data, stream)
else:
    yaml.dump(data, stream, exclude=['conditional_attr'])

当然这实际上不起作用,但是有什么方法可以实现这种行为吗?

【问题讨论】:

    标签: python yaml pyyaml python-dataclasses ruamel.yaml


    【解决方案1】:

    我认为排除某些映射键作为转储方法的一个选项并不是一个好主意。

    除此之外,ruamel.yaml 已经有一个 documented method to do special dumps 可以用来过滤掉 任何属性,例如对于那些名字以conditional_开头的人:

    import sys
    from dataclasses import dataclass
    from ruamel.yaml import yaml_object, YAML
    
    yaml = YAML()
    
    verbose_output = False
    
    @yaml_object(yaml)
    @dataclass
    class DataObject:
        normal_attr: str
        normal_attr_2: str
        conditional_attr: str
    
        @classmethod
        def to_yaml(cls, representer, node):
            d = {}
            for k in node.__annotations__:
                if not verbose_output and k.startswith('conditional_attr'):
                    continue
                d[k] = node.__getattribute__(k)
            return representer.represent_mapping('!DataObject', d)
    
    data = DataObject(normal_attr='a', normal_attr_2='b', conditional_attr='c')
    
    yaml.dump(data, sys.stdout)
    

    这给出了:

    !DataObject
    normal_attr: a
    normal_attr_2: b
    

    【讨论】:

    • 我认为在序列化时指定字段是理想的。这就是 Marshmallow 所做的:marshmallow.readthedocs.io/en/stable/…
    • 无论如何,这个答案是一个开始,但verbose_output 是一个全局变量,它实际上并不能解决我的问题,因为你不能合理地创建一个可重用的模块来允许用户配置详细程度。
    • verbose_output 是您代码中的全局变量,这就是为什么我在这里继续使用它的原因。如果您有一个序列化例程,添加参数可能没问题,但 ruamel.yaml(和 PyYAML)有多个序列化,都需要使用某人提出的每个新参数进行更新。 IMO 以每个序列化程序都可以使用的面向对象的方式执行此操作更有效。
    • 如果我需要这样的东西,我不会像你那样使用全局变量,而是添加属性yaml.verbose_dataclass_output = False。并为 yaml_object 创建一个替代装饰器,它仍然将 YAML 实例作为参数,但将 to_yaml 类方法(检查 verbose_data_class 属性)添加到它装饰的每个类。
    猜你喜欢
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2020-12-25
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-15
    相关资源
    最近更新 更多