在collections.defaultdict中使用键

16 投票
3 回答
4979 浏览
提问于 2025-04-17 05:24

collections.defaultdict 是个很不错的工具,特别是和 lambda 一起使用的时候。

>>> import collections
>>> a = collections.defaultdict(lambda : [None,None])
>>> a['foo']
[None, None]

有没有办法在 lambda 里使用给定的键(比如 'foo')呢?举个例子(这个是不能用的):

>>> a = collections.defaultdict(lambda : [None]*key)
>>> a[1]
[None]
>>> a[2]
[None, None]
>>> a
defaultdict(<function <lambda> at 0x02984170>, {1: [None], 2: [None, None]})

3 个回答

1

这样做可以达到你想要的效果,虽然这可能不是最好的解决办法(你需要先用默认的方式初始化它,然后就不要再用了)。可能通过重写其他一些方法可以解决这个问题。

class NoneDict(collections.defaultdict):
    def __setitem__(self, key, value):
        super(NoneDict, self).__setitem__(key, key*[None])
4

结合了来自 SingleNegationEliminationrplnt 的回答,以及 defaultdict 的文档,我使用了以下解决方案。

import collections
class KeyBasedDefaultDict(collections.defaultdict):
    def __missing__(self, key):
        if self.default_factory is None:
            raise KeyError(key)
        self[key] = self.default_factory(key)
        return self[key]

这个方法的主体其实可以简单写成 return self.default_factory(key),不过加上额外的代码可以确保它能完全模拟 defaultdict 的所有行为。

用法如问题中所述:

d = KeyBasedDefaultDict(lambda key: [None] * key)
d[1]
> [None]
d[2]
> [None, None]
32

你可能想要使用 __missing__ 这个功能。当你试图访问一个字典中不存在的项目时,它会被调用。默认情况下,__missing__ 会抛出一个错误,但在你自己创建的子类中,你可以根据需要做任何事情:

class A(dict):
    def __missing__(self, key):
        value = self[key] = [None] * key
        return value

撰写回答