关于python:有没有一种聪明的方法将密钥传递给defaultdict的default_factory?

Is there a clever way to pass the key to defaultdict's default_factory?

类具有一个采用一个参数的构造函数:

1
2
3
4
class C(object):
    def __init__(self, v):
        self.v = v
        ...

在代码的某个地方,对于dict中的值来说,知道它们的键是很有用的。我想使用默认dict,并将密钥传递给新生儿默认值:

1
d = defaultdict(lambda : C(here_i_wish_the_key_to_be))

有什么建议吗?


它很难被认为是聪明的——但是子类化是你的朋友:

1
2
3
4
5
6
7
8
9
10
class keydefaultdict(defaultdict):
    def __missing__(self, key):
        if self.default_factory is None:
            raise KeyError( key )
        else:
            ret = self[key] = self.default_factory(key)
            return ret

d = keydefaultdict(C)
d[x] # returns C(x)


不,没有。

不能将defaultdict实现配置为将缺少的key传递到开箱即用的default_factory。您唯一的选择是实现您自己的defaultdict子类,如上面@jochenritzel建议的那样。

但这并不"聪明",也不像标准的库解决方案那样干净(如果它存在的话)。因此,对你简明扼要的"是/否"问题的答案显然是"否"。

可惜的是,标准库缺少了一个如此频繁需要的工具。


我认为你根本不需要在这里。为什么不直接用dict.setdefault方法?

1
2
3
>>> d = {}
>>> d.setdefault('p', C('p')).v
'p'

当然,这将产生许多C的实例。如果这是一个问题,我认为更简单的方法可以做到:

1
2
>>> d = {}
>>> if 'e' not in d: d['e'] = C('e')

它比defaultdict或其他任何替代品都要快。

关于in试验与使用Try试验的速度的ETA,除非条款:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
>>> def g():
    d = {}
    if 'a' in d:
        return d['a']


>>> timeit.timeit(g)
0.19638929363557622
>>> def f():
    d = {}
    try:
        return d['a']
    except KeyError:
        return


>>> timeit.timeit(f)
0.6167065411074759
>>> def k():
    d = {'a': 2}
    if 'a' in d:
        return d['a']


>>> timeit.timeit(k)
0.30074866358404506
>>> def p():
    d = {'a': 2}
    try:
        return d['a']
    except KeyError:
        return


>>> timeit.timeit(p)
0.28588609450770264