从字典中获取单个键的最佳方法是什么?

19

如果你有一个Python字典,并且知道它只包含一个键/值对,那么检索该单个唯一项的最佳方法是什么?

到目前为止,我知道我可以使用以下两种方式之一:

  1. list(mydict.keys())[0]

  2. next(iter(mydict))

据我所知,list 的性能比 iter 差,因此后一种方法应该更好,对吗?哪种方法更好?是否有比我提到的这两种方法更好的方法?请告诉我。


在字典中,没有所谓的“第一”,因为它不是有序的。只有键是唯一的,值可以重复而不会出现问题。请在此描述您要解决的问题。 - Burhan Khalid
你想如何处理键/值对?在Python3中,使用for循环进行迭代是一种常见的方法。你可以使用for key, value in mydict.items(): - cdarke
在Python3中,默认情况下,字典会保持插入顺序。因此从技术上讲,是有顺序的。如果您先添加键/值'a',然后是'b'和'c',那么.keys()操作符应该按照这个顺序返回它们。 - Erich
4
@Erich:这只是在Python3.6之后才成立的事实,并且这种行为“不应被依赖”。请参考https://docs.python.org/3/whatsnew/3.6.html#new-dict-implementation。 - FabienP
@FabienP:我认为你是对的...并且感谢你提供参考链接! - danicotra
显示剩余2条评论
3个回答

33

哪种方法最好?

我建议使用next(iter(d))而不是list(mydict.keys())[0]来从字典中检索一个键。正如你所猜测的那样,使用next(iter(d))在效率上要好得多。

可以通过计时每种方法来观察效率差异:

>>> import timeit
>>> setup='from string import ascii_letters; d = {k: v for k, v in enumerate(ascii_letters)}'
>>> timeit.timeit(stmt='list(d.keys())[0]', setup=setup)
1.0895291733333334
>>> timeit.timeit(stmt='next(iter(d))', setup=setup)
0.2682935466666656

随着字典大小的增加,使用next(iter(d))而不是list(d.keys())[0]的选择变得非常明显:

>>> setup='d = {k: v for k, v in enumerate(range(500, 10000))}'
>>> timeit.timeit(stmt='list(d.keys())[0]', setup=setup)
98.52252842666667
>>> timeit.timeit(stmt='next(iter(d))', setup=setup)
0.2720192000000452

next(iter(d))的性能要比list(d.keys())[0]好得多,主要是因为它避免了在内存中创建所有字典键的潜在巨大列表,当它只需要第一个元素时。


好的,谢谢。所以next(iter(d))list(d.keys())[0]更好;这也是最好的方法吗? - danicotra
1
“指令越少”与“更高效”之间的相关性非常微弱。执行指令所需的时间变化很大,特别是对于CALL_FUNCTION等指令。 - user2357112
@user2357112 没错,这是一个很好的观点。但是,我也提供了时间数据,我相信它们可以很好地展示这两种方法的效率,并且有助于支持我的论点。 - Christian Dean
1
时间安排得很好,实际上讨论next(iter(d))不会创建的巨大不必要列表的部分也很好,但是关于“使用更少的指令,因此更有效”的部分是无效的推断。我建议只删除反汇编和从中得出的结论。 - user2357112
1
@user2357112 经过更多的研究,我明白了你的观点。当你说指令的执行时间可能会有所不同,特别是对于函数调用时,我明白你的意思了。谢谢你的解释。我现在同意那是一个薄弱的论点。我会将其删除。 - Christian Dean
@ChristianDean,使用next(iter())获取单个值是否也可以,而不是使用[*dict.values()][0]] - Bilal

6

由于问题假设字典只有一个键值对,除了接受的答案,我想再添加两种方法。

  • 使用dict.popitem()[0]popitem()以元组形式返回仅有的键值对:(key, value)。 如果您不想改变原始字典,请先进行复制。
  • 创建一个集合,然后弹出:set(mydict).pop()

在Python 3.9.6中进行简单的性能比较:

In [11]: import timeit

In [12]: timeit.timeit(stmt='d={1:2}; d.popitem()[0]')
Out[12]: 0.15144950605463237

In [13]: timeit.timeit(stmt='d={1:2}; next(iter(d))')
Out[13]: 0.1860927080269903

In [14]: timeit.timeit(stmt='d={1:2}; set(d).pop()')
Out[14]: 0.19704585697036237

In [15]: timeit.timeit(stmt='d={1:2}; list(d)[0]')
Out[15]: 0.2412048210389912

感谢您在此方面的额外贡献。 - danicotra
如果这个字典非常庞大怎么办?展示一个海量字典的timeit更新将会很棒。 - Austin Heller
有多大?一个字典键或值占用一半的系统内存? - alick

2
要从字典中获取“第一个”键值对,您需要使用OrderedDict

from collections import OrderedDict
d = OrderedDict()

#add items as normal

first_key = [a for a, b in d.items()][0]
print(d[first_key])

谢谢,我不知道有OrderedDict。 - danicotra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接