setdefault vs defaultdict performance

时间:2016-07-28 01:13:57

标签: python dictionary defaultdict setdefault

我正在为性能很重要的应用程序编写代码。我想知道为什么defaultdict似乎比setdefault更快。

我希望能够使用setdefault,主要是因为我不喜欢嵌套defaultdict的打印输出(请参阅下面的实现)。

在我的代码中,我需要测试element_id是否已经是dict的关键。

以下是我正在测试的两个功能:

def defaultdictfunc(subcases,other_ids,element_ids):
    dict_name= defaultdict(lambda: defaultdict(lambda: defaultdict(dict)))
    for subcase in subcases:
        for other_id in other_ids:
            for element_id in element_ids: 
                if element_id in dict_name[subcase][other_id]:
                    # error duplicate element_id
                    pass
                else:
                    dict_name[subcase][other_id][element_id]=0
    return dict_name

def setdefaultfunc(subcases,other_ids,element_ids):
    dict_name={}
    for subcase in subcases:
        for other_id in other_ids:
            for element_id in element_ids: 
                if element_id in dict_name.setdefault(subcase,{}).setdefault(other_id,{}):
                    # error duplicate element_id
                    pass
                else:
                    dict_name[subcase][other_id][element_id]=0

    return dict_name

IPython输入和输出:

In [1]: from numpy.random import randint

In [2]: subcases,other_ids,element_ids=(randint(0,100,100),randint(0,100,100),randint(0,100,100))

In [5]: from collections import defaultdict

In [6]: defaultdictfunc(subcases,other_ids,element_ids)==setdefaultfunc(subcases,other_ids,element_ids)
Out[6]: True

In [7]: %timeit defaultdictfunc(subcases,other_ids,element_ids)
10 loops, best of 3: 177 ms per loop

In [8]: % timeit setdefaultfunc(subcases,other_ids,element_ids)
1 loops, best of 3: 351 ms per loop

为什么setdefaultfunc会变慢。我认为底层代码是一样的。有没有办法提高速度?

由于

2 个答案:

答案 0 :(得分:1)

setdefaultfunc最糟糕,因为您在循环中多次调用dict构造函数(因为{}等效于dict()),而defaultdict则避免了这种情况设计。

只需少量更改,就可以轻松改善setdefaultfunc

def setdefaultfunc2(subcases,other_ids,element_ids):
    dict_name={}
    for subcase in subcases:
        subcase_dict = dict_name.setdefault(subcase,{})
        for other_id in other_ids:
            other_id_dict = subcase_dict.setdefault(other_id,{})
            for element_id in element_ids: 
                if element_id in other_id_dict:
                    # error duplicate element_id
                    pass
                else:
                    other_id_dict[element_id]=0
    return dict_name

进行此更改后,我的计算机中的结果为:

In [37]: defaultdictfunc(subcases,other_ids,element_ids)==setdefaultfunc2(subcases,other_ids,element_ids)
Out[37]: True

In [38]: %timeit defaultdictfunc(subcases,other_ids,element_ids)
286 ms ± 8.55 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [39]: %timeit setdefaultfunc(subcases,other_ids,element_ids)
434 ms ± 1.78 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [40]: %timeit setdefaultfunc2(subcases,other_ids,element_ids)
174 ms ± 348 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

IMO,defaultdict不能提供足够的性能提升,因此值得使用。

答案 1 :(得分:0)

根据用户aneroid

  

defaultdictdict.setdefault()更快是有道理的,因为前者在创建时为整个dict设置了默认值,而setdefault()在读取时为每个元素执行它。使用setdefault的一个原因是,您指定的默认值基于键(或某些内容),而不是整个dict的通用默认值。