【问题标题】:How to remove a key/value pair from yaml dump, in Python?如何在 Python 中从 yaml 转储中删除键/值对?
【发布时间】:2016-03-03 06:18:08
【问题描述】:

假设我有一个简单的类定义:

import yaml
class A:
    def __init__(self):
        self.abc = 1
        self.hidden = 100
        self.xyz = 2

    def __repr__(self):
        return yaml.dump(self)

A()

打印

!!python/object:__main__.A
abc: 1
hidden: 100
xyz: 2

有没有一种干净的方法可以从 yaml 转储的打印输出中删除包含 hidden: 100 的行?键名hidden 是预先知道的,但它的数字 值可能会改变。

期望的输出:

!!python/object:__main__.A
abc: 1
xyz: 2

仅供参考:此转储仅用于显示,不会被加载。

我想可以使用yaml.representative 来抑制 key=hidden 的键/值对。另一种方法是在字符串输出中使用 RegEx 查找 hidden: [number]

【问题讨论】:

  • hidden 需要是类的属性吗?它可以是类内的全局变量吗?
  • @erip:类中的全局是什么意思? self.hidden 也在类范围内:)
  • 不要成为self 的成员(即self.hidden = "foo"),而是使用hidden = "foo" 使其成为全局类。根据应用程序,这可能不是一个好主意,但这是一个建议。
  • re.sub('hidden: \d+\n', '', s), '\n'.join([l for l in s.splitlines() if not l.startswith('hidden:')]),但我不会那样做,我会寻找一种方法来改变 yaml.dump 的行为。
  • 我认为您使用了错误的工具来完成这项工作。 YAML 用于编码数据(主要是文件)。 __repr__ 用于显示对象。

标签: python regex string python-3.x yaml


【解决方案1】:

我查看了 pyyaml 的文档,但没有找到实现您目标的方法。解决方法是删除属性hidden,调用yaml.dump,然后重新添加:

    def __repr__(self):
        hidden = self.hidden
        del self.hidden

        return yaml.dump(self)

        self.hidden = hidden

退一步,为什么要用yaml代替__repr__?你能自己动手而不是依赖yaml吗?

【讨论】:

    【解决方案2】:

    json 是成熟的解决方案,并且(在撰写本文时)拥有比 pyyaml 更好的文档;
    我会改用它,而 pyyaml 的文档很难完全理解。作为奖励,YAML(几乎)是 JSON 的超集,因此您无需转换即可将数据读取为 YAML。
    但是,要轻松使用 YAML 的所有优点,您可能必须进行转换数据到 YAML

    json模块默认无法序列化自定义对象,但可以轻松扩展:

    import json
    
    def default(o):
        if isinstance(o, A):
            result = vars(o).copy()
            del result['hidden']
            result['__class__'] = o.__class__.__name__
            return result
        else:
            return o
    
    json.dumps(A(), default=default) # => '{"__class__": "A", "xyz": 2, "abc": 1}'
    

    如果你不想在dumps 的任何地方写default=default,你可以创建自定义序列化器:

    dumper = json.JSONEncoder(default=default)
    dumper.encode(A()) # => '{"__class__": "A", "xyz": 2, "abc": 1}'
    

    或者,能够通过子类轻松地进一步扩展它:

    class Dumper(json.JSONEncoder):
        __slots__ = ()
        def default(self, o):
            if isinstance(o, A):
                result = vars(o).copy()
                del result['hidden']
                result['__class__'] = o.__class__.__name__
                return result
            else:
                return super().default(o)
    
    dumper = Dumper()
    dumper.encode(A()) # => '{"__class__": "A", "xyz": 2, "abc": 1}'
    

    请注意,JSON 中的字段是无序的。
    另外,如果你想使用这个,我建议你不要序列化带有键__class__的dict,因为它可能很难将它与序列化的对象区分开来。

    See it working online

    【讨论】:

    • 谢谢。我仍然觉得json 产生于yaml,它(默认情况下)在打印输出中省略引号(在键名上)。我的对象有很多键值对。目标是在屏幕上转储一个漂亮的结构以供进一步分析。我想抑制一些管家键/值对。我只需几行就可以成功完成大部分工作。只需要在一两行中隐藏那些管家:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-04
    • 2021-03-10
    • 2018-10-22
    • 2018-05-27
    • 2015-12-27
    • 2011-12-23
    相关资源
    最近更新 更多