当帮助我的同事解决问题时,我看到了一些我不知道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的。哪一个产生最佳性能?
答案 0 :(得分: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的键时,但是周围的代码d
并不明显。是dict
。
除此之外,您还询问了复杂性。
所有这些解决方案都具有相同的(线性)复杂性,因为它们在封面下都做同样的事情:对于字典中的每个键,将其附加到列表的末尾。这是每个键的一步,并且每个步骤的复杂性是分摊的常量(因为Python列表以指数方式扩展),因此标题时间为O(N)
,其中N
是字典的长度。
答案 1 :(得分: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