字典访问速度与字符串键的整数键比较

时间:2011-12-06 16:53:58

标签: python dictionary

我有一本很大的字典,我必须多次查阅这些字典。我的键是整数,但代表标签,所以不需要添加,减去等...我最终试图评估字符串键和整数键字典之间的访问时间,这是结果。

from timeit import Timer

Dint = dict()
Dstr = dict()

for i in range(10000):
    Dint[i] = i
    Dstr[str(i)] = i


print 'string key in Dint',
print(Timer("'7498' in Dint", "from __main__ import Dint").timeit(100000000))
print 'int key in Dint',
print(Timer("7498 in Dint", "from __main__ import Dint").timeit(100000000))
print 'string key in Dstr',
print(Timer("'7498' in Dstr", "from __main__ import Dstr").timeit(100000000))
print 'int key in Dstr',
print(Timer("7498 in Dstr", "from __main__ import Dstr").timeit(100000000))

每次重复运行之间产生轻微变化:

string key in Dint 4.5552944017
int key in Dint 7.14334390267
string key in Dstr 6.69923791116
int key in Dstr 5.03503126455

是否证明使用带字符串的字典作为键比使用整数作为键更快?

3 个答案:

答案 0 :(得分:21)

CPython的dict实现实际上已针对字符串键查找进行了优化。有两个不同的函数,lookdictlookdict_string(Python 3中的lookdict_unicode),可用于执行查找。 Python将使用字符串优化版本,直到搜索非字符串数据,之后使用更通用的函数。您可以通过下载CPython的源代码并阅读dictobject.c来查看实际实现。

由于此优化,当dict包含所有字符串键时,查找速度会更快。

答案 1 :(得分:5)

我担心你的时代并不是真的非常证明。

你在Dint中对字符串的测试是最快的:一般来说,测试任何不在字典中的东西很可能很快,但这只是因为你很幸运,第一次点击一个空单元格,所以查找可以终止。如果你运气不好并且选择了一个达到一个或多个完整单元格的值,那么它最终会比实际找到的东西慢。

测试字典中的任意字符串必须计算字符串的哈希码。这需要时间与字符串的长度成比例,但Python有一个巧妙的技巧,只为每个字符串计算一次。由于您在计时测试中反复使用相同的字符串,因此计算哈希值所花费的时间会丢失,因为它只会在第一次发生而不会发生在其他99999999次。如果你每次使用不同的字符串时会得到一个非常不同的结果。

Python优化了字典代码,其中键是字符串。总的来说,您应该发现使用字符串键多次使用相同的键会稍快一些,但如果您必须在查找之前将整数转换为字符串,那么您将失去这一优势。

答案 2 :(得分:0)

这也是我的问题。显然,带有字符串键的字典效率更高,但是访问时间确实很接近。我使用Python 3运行了以下代码:

import random
import timeit
import uuid

DICT_INT = dict()
DICT_STR = dict()
DICT_MIX = dict()

for i in range(2000000):
    DICT_INT[i] = uuid.uuid4().hex
    DICT_STR[str(i)] = uuid.uuid4().hex
    DICT_MIX[i if random.randrange(2) else str(i)] = uuid.uuid4().hex

def int_lookup():
    int_key = random.randrange(len(DICT_INT))
    str_key = str(int_key)
    mix_key = int_key if int_key % 2 else str_key
    return int_key in DICT_INT

def str_lookup():
    int_key = random.randrange(len(DICT_STR))
    str_key = str(int_key)
    mix_key = int_key if int_key % 2 else str_key
    return str_key in DICT_STR

def mix_lookup():
    int_key = random.randrange(len(DICT_MIX))
    str_key = str(int_key)
    mix_key = int_key if int_key % 2 else str_key
    return mix_key in DICT_MIX

print('Int dict lookup: ', end='')
print(timeit.timeit('int_lookup', 'from __main__ import int_lookup', number=1000000000))
print('Str dict lookup: ', end='')
print(timeit.timeit("str_lookup", 'from __main__ import str_lookup', number=1000000000))
print('Mix dict lookup: ', end='')
print(timeit.timeit("mix_lookup", 'from __main__ import mix_lookup', number=1000000000))

这是结果:

Int dict lookup: 12.395361029000014
Str dict lookup: 12.097380312000041
Mix dict lookup: 12.109765773000163