代码之家  ›  专栏  ›  技术社区  ›  Sam R. chikka.anddev

带有混合数据类型的Python嵌套defaultdict

  •  6
  • Sam R. chikka.anddev  · 技术社区  · 10 年前

    那么,我该如何为此创建默认dict:

    {
        'branch': {
            'count': 23,
            'leaf': {
                'tag1': 30,
                'tag2': 10
            }
        },
    }
    

    所以,我会得到0 count , tag1 tag2 作为默认值?我想在读取输入时动态填充dict。当我看到一个新的 branch 我想用 计数 作为零,空字典作为叶。当我得到 leaf ,我想用它的名称创建一个键,并将值设置为零。

    使现代化 : 接受了Martijn的答案,因为它有更多的支持票,但其他答案也同样好。

    3 回复  |  直到 10 年前
        1
  •  5
  •   Martijn Pieters    10 年前

    你不能这样做 defaultdict ,因为工厂无法访问密钥。

    然而,你 可以 just子类 dict 创建自己的“智能” 默认词典 -像班级一样。提供您自己的 __missing__ method 基于以下键添加值:

    class KeyBasedDefaultDict(dict):
        def __init__(self, default_factories, *args, **kw):
            self._default_factories = default_factories
            super(KeyBasedDefaultDict, self).__init__(*args, **kw)
    
        def __missing__(self, key):
            factory = self._default_factories.get(key)
            if factory is None:
                raise KeyError(key)
            new_value = factory()
            self[key] = new_value
            return new_value
    

    现在,您可以提供自己的映射:

    mapping = {'count': int, 'leaf': dict}
    mapping['branch'] = lambda: KeyBasedDefaultDict(mapping)
    
    tree = KeyBasedDefaultDict(mapping)
    

    演示:

    >>> mapping = {'count': int, 'leaf': dict}
    >>> mapping['branch'] = lambda: KeyBasedDefaultDict(mapping)
    >>> tree = KeyBasedDefaultDict(mapping)
    >>> tree['branch']['count'] += 23
    >>> tree['branch']['leaf']['tag1'] = 30
    >>> tree['branch']['leaf']['tag2'] = 10
    >>> tree
    {'branch': {'count': 23, 'leaf': {'tag1': 30, 'tag2': 10}}}
    
        2
  •  3
  •   Aaron Hall    10 年前

    对象具有 __dict__ 它存储数据,并允许您以编程方式设置默认值。还有一个叫做 Counter 我认为你应该用它来授权清点你的叶子。

    因此,我建议您使用带有集合的对象。计数器:

    import collections
    
    class Branch(object):
        def __init__(self, leafs=(), count=0):
            self.leafs = collections.Counter(leafs)
            self.count = count
        def __repr__(self):
            return 'Branch(leafs={0}, count={1})'.format(self.leafs, self.count)
    
    BRANCHES = [Branch(['leaf1', 'leaf2']),
                Branch(['leaf3', 'leaf4', 'leaf3']),
                Branch(['leaf6', 'leaf7']),
               ]
    

    和用法:

    >>> import pprint
    >>> pprint.pprint(BRANCHES)
    [Branch(leafs=Counter({'leaf1': 1, 'leaf2': 1}), count=0),
     Branch(leafs=Counter({'leaf3': 2, 'leaf4': 1}), count=0),
     Branch(leafs=Counter({'leaf7': 1, 'leaf6': 1}), count=0)]
    >>> first_branch = BRANCHES[0]
    >>> first_branch.count += 23
    >>> first_branch
    Branch(leafs=Counter({'leaf1': 1, 'leaf2': 1}), count=23)
    >>> first_branch.leafs['leaf that does not exist']
    0
    >>> first_branch.leafs.update(['new leaf'])
    >>> first_branch
    Branch(leafs=Counter({'new leaf': 1, 'leaf1': 1, 'leaf2': 1}), count=23)
    
        3
  •  2
  •   Sam R. chikka.anddev    9 年前

    回答我自己的问题,但我认为这也会奏效:

    def branch():
        return {
            'count': 0,
            'leaf': defaultdict(int)
        }
    
    tree = defaultdict(branch)
    tree['first_branch']['leaf']['cat2'] = 2
    print json.dumps(tree, indent=2)
    
    # {
    #   "first_branch": {
    #     "count": 0, 
    #     "leaf": {
    #       "cat2": 2
    #     }
    #   }
    # }