通过嵌套字典迭代

时间:2017-03-05 17:07:35

标签: python dictionary

我正在尝试实现从字典继承的简单树类。 这是我的代码:

class tree(dict):
    def __init__(self, hsymbol="/"):
        self.hsymbol = hsymbol
    def __setitem__(self, key, value):
        if key[0] == self.hsymbol : key = key[1:]
        parts = key.split(self.hsymbol, 1)
        if len(parts) == 2:
            if parts[0] not in self: self[parts[0]] = tree(hsymbol = self.hsymbol)
            self[parts[0]].__setitem__(parts[1], value)
        else:
            super(tree, self).__setitem__(key, value)

    def __getitem__(self, key):
        if key[0] == self.hsymbol : key = key[1:]
        parts = key.split(self.hsymbol, 1)
        if len(parts) == 2:
            if parts[0] not in self: raise KeyError(parts[0])
            return self[parts[0]][parts[1]]
        else:
            if key not in self: raise KeyError(parts[0])
            return super(tree, self).__getitem__(key)
    def __contains__(self,key):
        if key[0] == self.hsymbol : key = key[1:]
        parts = key.split(self.hsymbol, 1)
        if len(parts) == 2:
            if not super(tree, self).__contains__(parts[0]): return False
            return parts[1] in self[parts[0]]
        else:
            if not super(tree, self).__contains__(key): return False
            return True
    def __delitem__(self, key):
        if key[0] == self.hsymbol : key = key[1:]
        parts = key.split(self.hsymbol, 1)
        if len(parts) == 2:
            if parts[0] not in self: raise KeyError(parts[0])
            self[parts[0]].__delitem__(parts[1])
        else:
            if key not in list(self): raise KeyError(parts[0])
            super(tree,self).__delitem__(key)
    def keys(self,parent=""):
        #if parent is None: parent = self.hsymbol
        names = []
        for name in super(tree, self).keys():
            if isinstance(self[name], tree):
                names += self[name].keys(parent=parent+self.hsymbol+name)
            else:
                names.append(parent+self.hsymbol+name)
        return names

所以一切都很顺利,虽然我不确定键功能的实现:

>>> t=tree()
>>> t['/user/Johnson/incoming'] = 2200
>>> t['/user/Johnson/family'] = 4
>>> t['/user/Johnson/play'] = False
>>> t['/user/Smith/incoming'] = 12000
>>> t['/user/Smith/family'] = 1
>>> t['/user/Smith/play'] = True
>>> t['user/Smith/incoming']
12000    
>>> print t
{'user': {'Smith': {'play': True, 'incoming': 12000, 'family': 1}, 'Johnson': {'play': False, 'incoming': 2200, 'family': 4}}}
>>> print t.keys()
['/user/Smith/play', '/user/Smith/incoming', '/user/Smith/family', '/user/Johnson/play', '/user/Johnson/incoming', '/user/Johnson/family']
>>> t
{'user': {'Smith': {'play': True, 'incoming': 12000, 'family': 1}, 'Johnson': {'play': False, 'incoming': 2200, 'family': 4}}}

...但不是通过它的迭代:

>>> for k in t:
...  print k
... 
user
>>> 

我怎样才能得到这样的东西?

/user/Smith/play
/user/Smith/incoming
/user/Smith/family
/user/Johnson/play
/user/Johnson/incoming
/user/Johnson/family

非常确定它必须是树类的__iter__next属性,但我还没弄清楚如何编写它。

我在没有运气的情况下搜索了Stack Overflow:

  • python递归迭代嵌套词典

  • 从字典迭代继承的python类,通过嵌套字典

  • 通过嵌套词典进行python迭代

1 个答案:

答案 0 :(得分:1)

是的,您需要__iter__(迭代器会自动生成next()

遵循现有逻辑:

def __iter__(self, parent=""):
    for name in super(tree, self).keys():
        if isinstance(self[name], tree):
            for item in self[name].__iter__(parent=parent+self.hsymbol+name):
                yield item
        else:
            yield parent+self.hsymbol+name

与当前的keys()实现不同,它只根据需要遍历树:如果客户端只需要前两个键,则只调用next()两次,因此仅使用迭代器过了两个yield s。

(我可能建议将keys简化为return list(iter(self)) - 这样你就可以为那些想要避免不必要地走完整棵树的效率低的人提供懒惰的方法,而非懒惰否则)。