【问题标题】:iteration through nested dictionaries遍历嵌套字典
【发布时间】:2017-07-25 11:30:16
【问题描述】:

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

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迭代

【问题讨论】:

  • 在问题的初始版本中抱怨 dupehammer 持有者并不是建立……富有成效的工作关系的好方法。请记住,如果您的问题确实被关闭,那些无需其他四个选民同意就可以重新打开它的人?还有那些有徽章的。所以。 如果您的问题以您认为不重复的内容结束,请论证当时如何区分它;不要预先设置敌对立场。
  • 因为你继承自dict,所以当你遍历你正在调用dict.__iter__的实例时;您的自定义 keys 方法将被忽略。考虑组合,而不是继承;实现MutableMappingABC,将包装好的字典作为属性。参见例如stackoverflow.com/a/3387975/3001761
  • @CharlesDuffy 但我只是厌倦了要求例如做一些没有功能的事情,并且得到它是重复的,所有事情都是由函数完成的......看看这个link...... .
  • 或者,将__iter__ 实现为return iter(self.keys())
  • 如果这个问题作为重复而被关闭,并且如果,在你实际尝试了答案之后对您的特定用例进行了适当修改的副本并发现它们不能解决您的问题,然后编辑问题以具体说明它们如何不能解决问题。不能保证您的问题不是骗子,如果骗子有您需要的答案,为什么不想向您展示它?

标签: python dictionary


【解决方案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() 两次,因此迭代器仅继续经过两个 @ 987654326@s.

(我可能会建议将keys 简单地实现为return list(iter(self))——这样您就可以为那些想要避免不必要地遍历整棵树的低效率的人使用惰性方法,否则使用非惰性方法)。

【讨论】:

  • 谢谢!优秀!这正是我要找的!
  • 请注意,如果 OP 确实使用了MutableMapping,它将为他们生成keys
猜你喜欢
  • 2013-07-21
  • 1970-01-01
  • 2015-12-06
相关资源
最近更新 更多