是否扩展了一个字典列表,而不是迭代密钥?

问题描述 投票:-1回答:2

在帮助我的同事解决问题时,我看到了一些我不知道python的事情。与其他方式相比,我很好奇性能和时间复杂性的堆积,最好的方法是为了性能。

我的同事做了什么促使这个问题:

list_of_keys = []
test_dict = {'foo': 1, 'bar': [1, 2, 3, 4, 5]}
list_of_keys.extend(test_dict)

print(list_of keys)

['foo','bar']

与我见过的其他例子:

list_of_keys = []
test_dict = {'foo': 1, 'bar': [1, 2, 3, 4, 5]}
for i in test_dict.keys():
    list_of_keys.append(i)

keys = list(test_dict)

为了简单地附加键,这些中的哪一个被证明是最有益的和最pythonic的。哪一个产生最佳性能?

python performance
2个回答
3
投票

正如the docs解释的那样,s.extend(t)

使用s的内容扩展t(大部分与s[len(s):len(s)] = t相同)

好的,所以不清楚它是否应该比循环中调用append更快或更慢。但它更快一点 - 循环发生在C而不是Python中,它可以使用一些特殊的优化代码添加到列表中,因为它知道你没有同时触摸列表。

更重要的是,它更简单,更易读,更难出错。


至于从空列表开始然后扩展它(或附加到它),没有充分的理由这样做。如果您已经有一个包含某些值的列表,并且想要添加dict键,那么请使用extend。但是如果你只是想创建一个密钥列表,那就做list(d)


至于d.keys()d,真的没什么区别。无论你迭代dict还是它的dict_keys视图,你都会得到完全相同的迭代值,即使使用完全相同的dict_keyiterator。对keys()的额外调用确实让事情变得有点慢,但这是一个固定的成本,而不是每个元素一次,所以除非你的指标很小,否则你不会看到任何明显的差异。

那么,在这种情况下,哪一个看起来更具可读性。一般来说,你想要在d.keys()上循环的唯一原因就是当你想要明确表示你正在迭代dict的键时,但是从周围的代码来看,ddict并不明显。


除此之外,您还询问了复杂性。

所有这些解决方案都具有相同的(线性)复杂性,因为它们在封面下都做同样的事情:对于字典中的每个键,将其附加到列表的末尾。这是每个键的一步,并且每个步骤的复杂性是摊销常数(因为Python列表以指数方式扩展),因此标题时间是O(N),其中N是dict的长度。


1
投票

在@thebjorn提到模块之后。似乎调用extend是最快的

为了便于阅读和清洁,list()似乎是最pythonic。

最有益的似乎取决于用例。但是,或多或少这样做是多余的,如评论中所述。这是从一个错误中发现的,我很好奇。

timeit.timeit("for i in {'foo': 1, 'bar': [1, 2, 3, 4, 5]}.keys():[].append(i)", number=1000000)
0.6147394659928977

timeit.timeit("[].extend({'foo': 1, 'bar': [1, 2, 3, 4, 5]})", number=1000000)
0.36140396299015265

timeit.timeit("list({'foo': 1, 'bar': [1, 2, 3, 4, 5]})", number=1000000)
0.4726199270080542
© www.soinside.com 2019 - 2024. All rights reserved.