字典的有效键

时间:2018-08-09 19:25:22

标签: python dictionary key processing-efficiency memory-efficient

我是新来的人,所以我希望提供足够的细节。我试图找出键选择是否影响Python中词典的效率。我正在考虑的一些比较是:

  • 数字与字符串(例如my_dict[20]my_dict['twenty']快)
  • len字符串(例如my_dict['a']my_dict['abcdefg']快)
  • 在字典中混合键类型,例如使用数字,字符串和/或元组(例如my_dict = {0: 'zero', 2: 'two'}{0: 'zero', 'two': 2}执行得更快)

我无法从Google搜索中找到此主题,所以我想也许这里有人知道。

2 个答案:

答案 0 :(得分:1)

首先,我建议您了解How are Python's Built In Dictionaries Implemented

现在,让我们进行一些随机实验以证明该理论(至少部分地):

import timeit
import string
import random
import time


def random_str(N):
    return ''.join(
        random.choice(string.ascii_uppercase + string.digits) for _ in range(N)
    )


def experiment1(dct, keys):
    s = time.time()
    {dct[k] for k in keys}
    return time.time() - s


if __name__ == "__main__":
    N = 10000
    K = 200
    S = 50000
    dct1 = {random_str(K): None for k in range(N)}
    dct2 = {i: None for i in range(N)}
    keys1 = list(dct1.keys())
    keys2 = list(dct2.keys())

    samples1 = []
    samples2 = []
    for i in range(S):
        samples1.append(experiment1(dct1, keys1))
        samples2.append(experiment1(dct2, keys2))

    print(sum(samples1), sum(samples2))

    # print(
    #     timeit.timeit('{dct1[k] for k in keys1}', setup='from __main__ import dct1, keys1')
    # )

    # print(
    #     timeit.timeit('{dct2[k] for k in keys2}', setup='from __main__ import dct2, keys2')
    # )

我在包装盒上使用不同的抽样大小得到的结果是:

  • N = 10000,K = 200,S = 100 => 0.08300423622131348 0.07200479507446289
  • N = 10000,K = 200,S = 1000 => 0.885051965713501 0.7120392322540283
  • N = 10000,K = 200,S = 10000 => 8.88549256324768 7.005417346954346
  • N = 10000,K = 200,S = 50000 => 43.57453536987305 34.82594871520996

因此,您可以看到,无论您使用大的随机字符串来查找字典还是整数,性能都将保持几乎相同。您要考虑的唯一“实际”差异是两个字典的内存消耗。在将大量字典转储到磁盘或从磁盘转储大型字典时,这可能是相关的,在这种情况下,拥有紧凑形式的数据结构可能是值得的,这样您就可以在缓存/读取它们时节省几秒钟的时间。

NS:如果有人能够解释为什么使用timeit(带注释的部分)时我真的获得了很多成就,请让我...使用很少的实验常数,我将获得非常高的价值...这就是为什么我放弃它没有评论。如果您知道原因,请添加评论; D

答案 1 :(得分:0)

我也不知道答案,但是很容易测试。

from timeit import default_timer as timer
import string

#Create a few dictionaries, all the values are None
nums = range(1,27)
dict_numbers = dict.fromkeys(nums)

letters = string.ascii_lowercase
dict_singleLetter = dict.fromkeys(letters)

long_names = []
for letter in letters:
    long_names.append(''.join([letter, letters]))
dict_longNames = dict.fromkeys(long_names)

#Function to time thousands of runs to average out discrepancies
def testSpeed(dictionary, keys):
    x = None
    start = timer()
    for _ in range(1,100000):
        for i in keys:
            x = dictionary[i]
    end = timer()

    return str(end - start)

#Time the different dictionaries
print("Number took " + testSpeed(dict_numbers, nums) + " seconds")
print("Single letters took " + testSpeed(dict_singleLetter, letters) + " seconds")
print("Long keys took " + testSpeed(dict_longNames, long_names) + " seconds")

所有这些词典的长度相同,并且每个键包含相同的值。当我运行此命令时,长键字典实际上总是最快的,尽管只有5%。我可能没有意识到的其他细微差异可能导致了这种情况。数字和单个字母的速度相当接近,但是数字通常仅比单个字母快。希望这可以回答您的问题,并且此代码应该足够容易地进行扩展以测试混合的情况,但是我现在没有时间了。