18

私は、他の Python プログラマーがコレクション モジュールの defaultdict を次のユース ケースで使用しているのを見てきました。

from collections import defaultdict

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]

def main():
    d = defaultdict(list)
    for k, v in s:
        d[k].append(v)

私は通常、代わりに setdefault を使用してこの問題に取り組みました。

def main():
    d = {}
    for k, v in s:
        d.setdefault(k, []).append(v)

実際、ドキュメントはdefaultdict を使用する方が速いと主張していますが、自分自身をテストすると、反対のことが真であることがわかりました。

$ python -mtimeit -s "from withsetdefault import main; s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)];" "main()"
100000 loops, best of 3: 4.51 usec per loop
$ python -mtimeit -s "from withdefaultdict import main; s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)];" "main()"
100000 loops, best of 3: 5.38 usec per loop

テストの設定方法に何か問題がありますか?

参考までに、私は Python 2.7.3 [GCC 4.2.1 (Apple Inc. build 5666)] を使用しています。

4

1 に答える 1

25

はい、「間違った」ものがあります:

(default)dictセットアップの代わりにステートメントにの作成を入れました。new の構築はdefaultdict通常の よりもコストがかかります。通常dict、それはプログラムでプロファイリングする必要があるボトルネックではありません。結局のところ、データ構造は一度構築するだけで、何度も使用します。

以下のようなテストを行うと、defaultdict操作が実際に高速であることがわかります。

>>> import timeit
>>> setup1 = """from collections import defaultdict
... s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
... d = defaultdict(list)"""
>>> stmt1 = """for k, v in s:
...     d[k].append(v)"""
>>> setup2 = """s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
... d = {}"""
>>> stmt2 = """for k, v in s:
...     d.setdefault(k, []).append(v)"""
>>> timeit.timeit(setup=setup1, stmt=stmt1)
1.0283400125194078
>>> timeit.timeit(setup=setup2, stmt=stmt2)
1.7767367580925395

Win7 x64 上の Python 2.7.3。

于 2012-09-23T20:38:09.827 に答える