从列表中生成字典的最快方法,其中键 == 值

nor*_*ok2 2 python performance dictionary list

我有一个清单,说:

NUM = 100
my_list = list(range(NUM))
Run Code Online (Sandbox Code Playgroud)

我想生成一个dict键等于值的东西,比如:

my_dict = {item: item for item in my_list}
Run Code Online (Sandbox Code Playgroud)

或者:

my_dict = dict(zip(my_list, my_list))
Run Code Online (Sandbox Code Playgroud)

我已经运行了一些微基准测试,看起来它们的速度相似,但我希望第二个会更快,因为循环应该在 C 中发生。

例如,以下构造:

my_dict = {key: SOMETHING for key in keys}
Run Code Online (Sandbox Code Playgroud)

翻译成更快:

my_dict = dict.fromkeys(k, SOMETHING)
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是:有没有类似的这样的构造{x: x for x in my_list}


编辑

我已经检查过dir(dict),在这个方向上似乎没有任何东西(我希望它被称为类似的东西dict.fromitems())。


编辑 2

dict.fromitems()与此特定用例相比,类似的方法具有更广泛的应用,因为:

dict.fromitems(keys, values)
Run Code Online (Sandbox Code Playgroud)

原则上可以同时替代两者:

{k, v for k, v in zip(keys, values)}
Run Code Online (Sandbox Code Playgroud)

和:

dict(zip(keys, values))
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 7

不,没有更快的方法可用于字典。

那是因为性能成本全部在于处理迭代器中的每个项目、计算其散列并将键插入字典数据散列表结构中(包括动态增长这些结构)。相比之下,执行字典理解字节码真的微不足道。

dict(zip(it, it)){k: k for k in it} 并且dict.fromkeys(it)在速度上都接近:

>>> from timeit import Timer
>>> tests = {
...     'dictcomp': '{k: k for k in it}',
...     'dictzip': 'dict(zip(it, it))',
...     'fromkeys': 'dict.fromkeys(it)',
... }
>>> timings = {n: [] for n in tests}
>>> for magnitude in range(2, 8):
...     it = range(10 ** magnitude)
...     for name, test in tests.items():
...         peritemtimes = []
...         for repetition in range(3):
...             count, total = Timer(test, 'from __main__ import it').autorange()
...             peritemtimes.append(total / count / (10 ** magnitude))
...         timings[name].append(min(peritemtimes))  # best of 3
...
>>> for name, times in timings.items():
...     print(f'{name:>8}', *(f'{t * 10 ** 9:5.1f} ns' for t in times), sep=' | ')
...
dictcomp |  46.5 ns |  47.5 ns |  50.0 ns |  79.0 ns | 101.1 ns | 111.7 ns
 dictzip |  49.3 ns |  56.3 ns |  71.6 ns | 109.7 ns | 132.9 ns | 145.8 ns
fromkeys |  33.9 ns |  37.2 ns |  37.4 ns |  62.7 ns |  87.6 ns |  95.7 ns
Run Code Online (Sandbox Code Playgroud)

这是每项技术的每项成本表,从 100 到 1000 万项。随着哈希表结构增长的额外成本的累积,时间会增加。

当然,dict.fromkeys()可以处理一个项目稍微有点快,但它不是一个数量级比其他进程更快。它的(小)速度优势并非来自能够在 C 中迭代;区别纯粹在于不必每次迭代更新值指针;所有键都指向单个值引用。

zip()速度较慢,因为它构建了额外的对象(为每个键值对创建一个 2 项元组不是一个免费的操作),并且它增加了过程中涉及的迭代器的数量,你从字典的单个迭代器开始理解和dict.fromkeys(), 到 3 个迭代器(dict()迭代通过 委托zip()给两个单独的键和值迭代器)。

dict类中添加一个单独的方法来在 C 中处理这个问题是没有意义的,因为

  1. 无论如何都不是一个足够常见的用例(创建一个键和值相等的映射不是一个常见的需求)
  2. 无论如何,在 C 中不会比使用字典理解快得多。

  • @norok2:`list()` 可以更快,因为构建列表对象是一种简单的操作,当`items` 的大小已知时,您甚至可以预先确定新列表对象的大小。list comp 速度较慢,因为它必须在添加项目时动态调整大小,因为您无法再获取大小提示。字典*不能*预先确定大小,因此`dict.fromitems(keys, values)` **不** 会更快。 (2认同)