【问题标题】:How to ignore attributes when using yaml.dump?使用 yaml.dump 时如何忽略属性?
【发布时间】:2018-04-18 17:05:21
【问题描述】:

在对对象执行 YAML 转储时,我试图隐藏某些属性。我试过this的回答,它可以让你转储,但加载不起作用。

import yaml
from copy import deepcopy

class SecretYamlObject(yaml.YAMLObject):
    hidden_fields = []

    @classmethod
    def to_yaml(cls, dumper, data):
        new_data = deepcopy(data)
        for item in cls.hidden_fields:
            del new_data.__dict__[item]
        return dumper.represent_yaml_object(cls.yaml_tag, new_data, cls,
                                            flow_style=cls.yaml_flow_style)

class Trivial(SecretYamlObject):
    hidden_fields = ["_ignore"]
    yaml_tag = u'!!Trivial'
    def __init__(self):
        self.a = 1
        self.b = 2
        self._ignore = 3

运行此代码

import yaml
yaml.load('!Trivial {a: 1, b: 2}')

我收到以下错误:

ConstructorError: 无法确定标签的构造函数 '!Trivial' 在“”,第 1 行,第 1 列: !琐碎的{a: 1, b: 2}

我试图“破解”它,以便 yaml 可以使用 classproperty 找到构造函数,使用类似这样的东西:

class SecretYamlObject(yaml.YAMLObject):
    # ... same as before... remove for brevity

class Trivial(SecretYamlObject):
    hidden_fields = ["_ignore"]

    @classproperty # decorator definition not shown here for brevity 
    def yaml_tag(cls):
        return ('!!')+'python/object:'+'{}.{}'.format(cls.__module__, cls.__name__)

    def __init__(self):
        self.a = 1
        self.b = 2
        self._ignore = 3

这会产生一个错误的 yaml 字符串:

import yaml
from secret_yaml2 import Trivial
print yaml.dump(Trivial())

!%21python/object:secret_yaml2.Trivial {a: 1, b: 2}

由于某种原因,它将第二个 ! 转换为 %21... 这再次导致构造函数错误。

顺便说一句,下面的工作,但我需要在加载 yaml 之前知道对象的类,我可能不会。

import yaml
from secret_yaml import Trivial
yaml.load(yaml.dump(Trivial()))

我正在尝试创建一个知道如何正确地将自身转储到 yaml 的类,但我仍然可以通过正常的 yaml.load 调用来加载它。

【问题讨论】:

  • load()的调用不正常,不安全,因为它可以构造任意python对象,没有理由不使用safe_load()。确保您的 TrivialSecretYAMLObject 类具有 from_yaml class_method,否则 PyYAML 不知道如何加载标记的映射。
  • 我不明白的是,yaml 怎么知道使用那个方法?您首先需要导入“Trivial”,因此这是一个选项。通用对象序列化/反序列化不是这种情况。众所周知,yaml 是安全的。

标签: python serialization deserialization pyyaml


【解决方案1】:

您可以定义 Python 原生 pickle 和 PyYaml 都使用的 __getstate__

class A(object):
    def __init__(self):
        self.hidden = 42
        self.visible = 5

    def __getstate__(self):
        state = self.__dict__.copy()
        del state['hidden']
        return state

a = A()
d = yaml.dump(a)
print(d)

打印出来:

!!python/object:__main__.A
visible: 5

这是在 PyYaml 或 Pickle 等序列化程序中忽略或隐藏属性的最佳方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多