【问题标题】:Selectively dump object attributes with PyYAML使用 PyYAML 选择性地转储对象属性
【发布时间】:2012-10-02 11:17:40
【问题描述】:

我可以使用 YAML 转储 python 对象的层次结构,所以:

import yaml

class C():
    def __init__(self, x, y):
        self.x = x
        self.y = y

class D():
    def __init__(self, c, d):
        self.c = c
        self.d = d

d = D(c=C(x=1, y='hi'),
      d='bye')

print yaml.dump(d)

产生输出:

!!python/object:__main__.D
c: !!python/object:__main__.C {x: 1, y: hi}
d: bye

但我想选择性地隐藏一些属性。所以假设我有一个函数attribs_to_dump(obj),它对于任何对象都返回我要转储的属性名称列表,例如:

def attribs_to_dump(obj):
    if obj.__class__ == C: return ['x']
    if obj.__class__ == D: return ['c']

我的问题是,如何将attribs_to_dump 挂钩到yaml.dump 以便获得以下输出?

!!python/object:__main__.D
c: !!python/object:__main__.C {x: 1}

有一个复杂的因素:我想通过挂钩到 Yaml 来实现效果,因为它在对象层次结构上爬行,而不是通过自己预处理对象层次结构。原因是由于我正在使用的某些库中存在setattr/getattr/__dict__ 魔法,并非层次结构中的所有对象都易于自省:-(...

非常感谢所有帮助!

【问题讨论】:

    标签: python serialization yaml pyyaml


    【解决方案1】:

    这是一个有趣的问题,我很乐意解决它,谢谢:)

    from copy import deepcopy
    
    
    class C(object):
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
    class D(object):
        def __init__(self, c, d):
            self.c = c
            self.d = d
    
    d = D(
        c=C(x=1, y='hi'),
        d='bye'
    )
    
    
    FILTER_PARAMS = (
        #(class_reference, process_recursively, ['attributes', 'on', 'whitelist'])
        (D, True, ['c']),
        (C, False, ['x']),
    )
    
    def attr_filter(obj, filter_params):
        for attr in dir(obj):
            if attr.startswith('__'):
                # ignore builtins
                continue
    
            attr_val = obj.__getattribute__(attr)
            # loop through filter params
            for (cls, do_recursive, whitelist) in filter_params:
                if isinstance(obj, cls) and attr in whitelist:
                    # filter class matches the current obj's class and
                    # current attribute is on the whitelist
                    if do_recursive:
                        # must process this attribute the same way as the parent
                        setattr(obj, attr, attr_filter(attr_val, filter_params))                
                    # break will avoid the execution of the else clause meaning
                    # the attribute was on the white list so don't delete it
                    break
            else:
                # delete the current attribute of the instance as it was
                # not on the whitelist
                delattr(obj, attr)
    
        return obj
    
    
    # do a deepcopy of the object you pass in, so the original will be preserved
    filtered_instance = attr_filter(deepcopy(d), FILTER_PARAMS)
    print dir(filtered_instance)
    print dir(filtered_instance.c)
    
    # now pass filtered_instance to yaml's dump function
    

    【讨论】:

    • 您确实为我的问题提供了答案,但在我的情况下,deepcopy 不起作用,因为我正在序列化的对象非常神奇 - 元类魔法和非常深奥的 getattr/setattr 覆盖。我需要在问题中为游戏添加更多规则。
    猜你喜欢
    • 2021-01-10
    • 1970-01-01
    • 2020-03-11
    • 1970-01-01
    • 2010-10-10
    • 1970-01-01
    • 1970-01-01
    • 2017-08-08
    • 1970-01-01
    相关资源
    最近更新 更多