Pythonic将对象层次结构“扁平”为嵌套dicts的方法?

时间:2009-09-08 09:41:50

标签: python

我需要将对象“展平”为对象属性的嵌套dicts。我想要执行此操作的对象通常只是基本类型的容器或以类似方式起作用的其他对象。例如:

class foo(object):
    bar = None
    baz = None

class spam(object):
    eggs = []

x = spam()
y = foo()
y.bar = True
y.baz = u"boz"
x.eggs.append(y)

我需要“扁平化”这个:

{ 'eggs': [ { 'bar': True, 'baz': u'boz' } ] }

stdlib中有什么东西可以帮我吗?如果没有,我是否必须针对所有已知的基类型测试isinstance以确保我不会尝试转换无法转换的对象(例如:bool)?

修改

这些对象从外部库返回到我的代码,因此我无法控制它们。我可以在我的方法中使用它们,但将它们转换为dicts会更容易(更安全?) - 特别是对于单元测试。

4 个答案:

答案 0 :(得分:2)

代码:您可能需要处理其他可迭代类型:

def flatten(obj):
    if obj is None:
        return None
    elif hasattr(obj, '__dict__') and obj.__dict__:
        return dict([(k, flatten(v)) for (k, v) in obj.__dict__.items()])
    elif isinstance(obj, (dict,)):
        return dict([(k, flatten(v)) for (k, v) in obj.items()])
    elif isinstance(obj, (list,)):
        return [flatten(x) for x in obj]
    elif isinstance(obj, (tuple,)):
        return tuple([flatten(x) for x in obj])
    else:
        return obj

<强>错误吗 在您的代码中而不是:

class spam(object):
    eggs = []

x = spam()
x.eggs.add(...)

请做:

class spam(object):
    eggs = None #// if you need this line at all though

x = spam()
x.eggs = []
x.eggs.add(...)

如果不这样做,则spam的所有实例都将共享相同的eggs列表。

答案 1 :(得分:0)

不,标准库中没有任何内容。是的,你必须以某种方式测试类型是基本类型,如str,unicode,bool,int,float,long ......

你可能会创建一个方法的注册表来“序列化”不同的类型,但是这只有在某些类型不应该将所有它的属性序列化时才有用,或者如果你还需要展平类属性等等。

答案 2 :(得分:0)

几乎每个对象都有一个字典(称为__dict__)及其所有方法和成员 通过某些类型检查,您可以编写一个只筛选出您感兴趣的成员的函数。

这不是一项大任务,但正如chrispy所说,从完全不同的角度审视你的问题是值得的。

答案 3 :(得分:0)

嗯,我对此并不感到自豪,但可以做到以下几点:

  1. 创建一个具有序列化方法并遍历其属性的超类。
  2. 在运行时使用基础在运行时
  3. 扩展您的类
  4. 从新的超类中执行该类。它应该能够访问孩子们的 dict 数据并工作。
  5. 以下是一个例子:

    class foo(object):
        def __init__(self):
            self.bar = None
            self.baz = None
    
    class spam(object):
        delf __init__(self):
           self.eggs = []
    
    class Serializable():
        def serialize(self):
           result = {}
           for property in self.__dict__.keys():
               result[property] = self.__dict__[property]
           return result
    foo.__bases__ += (Serializable,)
    spam.__bases__ += (Serializable,)
    
    x = spam()
    y = foo()
    y.bar = True
    y.baz = u"boz"
    x.eggs.append(y)
    y.serialize()
    

    class foo(object): def __init__(self): self.bar = None self.baz = None class spam(object): delf __init__(self): self.eggs = [] class Serializable(): def serialize(self): result = {} for property in self.__dict__.keys(): result[property] = self.__dict__[property] return result foo.__bases__ += (Serializable,) spam.__bases__ += (Serializable,) x = spam() y = foo() y.bar = True y.baz = u"boz" x.eggs.append(y) y.serialize() 要指出的事情。如果你没有设置var是init, dict 将无法工作'因为它正在访问实例变量而不是类变量(我想你的意思是实例变量)。其次,确保Serializable不从对象继承,它是否会有

    希望它有所帮助!

    编辑:如果你只是复制 dict ,请使用deepcopy模块,这只是一个例子:P