【问题标题】:Most efficient method to check if dictionary key exists and process its value if it does检查字典键是否存在并处理其值的最有效方法
【发布时间】:2015-05-05 17:09:52
【问题描述】:
MyDict = {'key1':'value1', 'key2':'value2'}

我可以通过以下几种方式做到这一点:

if 'key1' in MyDict:
       var1 = MyDict['key1']

if MyDict.has_key('key1'):
       var1 = MyDict['key1']

或 罢工>

if MyDict['key1']:
    var1=MyDict['key1']

try: 
   var1=MyDict['key1]
except KeyError, e:
   pass

或者我尝试了类似的方法,但它在 python 中不能这样工作

if v=MyDict.get('key1'):
       var1=v

我们很可能会想出更多的工作方法来做到这一点。 就计算速度而言,哪一个效率最高?

【问题讨论】:

  • dict.has_key() 已被弃用,并在 Python 3 中消失。不要使用它。
  • 你的例子并不完全相同。前两个检查字典是否具有特定键,而第三个测试该键的布尔值(并假设它存在)。
  • @iCodez 但在这种情况下,空值将解析为 False,非空值将解析为 True - 这也有效,假设我的值中没有使用 0、False 或 None。对吗?
  • 如果'key1' 不是字典中的项目,前两个示例将正常工作,而第三个示例将引发KeyError 异常。
  • 密钥多久丢失一次?是的,这很重要。

标签: python performance dictionary


【解决方案1】:

给你的一个小基准(ipython):

In [1]: def test_1(d, k):
   ...:     if k in d:
   ...:         var1 = d[k]
   ...:         

In [2]: def test_2(d, k):
   ...:     if d.has_key(k):
   ...:         var1 = d[k]
   ...:         

In [3]: def test_3(d, k):
   ...:     try:
   ...:         var1 = d[k]
   ...:     except KeyError as e:
   ...:         pass
   ...:     

In [4]: def test_4(d, k):
   ...:     if d.get(k):
   ...:         var1 = d[k]
   ...:         

In [5]: my_dict = {'key{}'.format(i): 'value{}'.format(i) for i in range(1000)}

In [6]: key_valid = "key5"

In [7]: key_non_valid = "key"

In [8]: %timeit test_1(my_dict, key_valid)
10000000 loops, best of 3: 172 ns per loop

In [9]: %timeit test_1(my_dict, key_non_valid)
10000000 loops, best of 3: 132 ns per loop

In [10]: %timeit test_2(my_dict, key_valid)
1000000 loops, best of 3: 211 ns per loop

In [11]: %timeit test_2(my_dict, key_non_valid)
10000000 loops, best of 3: 171 ns per loop

In [12]: %timeit test_3(my_dict, key_valid)
10000000 loops, best of 3: 151 ns per loop

In [13]: %timeit test_3(my_dict, key_non_valid)
1000000 loops, best of 3: 1.07 µs per loop

In [14]: %timeit test_4(my_dict, key_valid)
1000000 loops, best of 3: 246 ns per loop

In [15]: %timeit test_4(my_dict, key_non_valid)
10000000 loops, best of 3: 189 ns per loop

结论:构造key in dict一般最快,仅优于try except在有效密钥的情况下,因为它不执行if操作。

(但请注意,try except 对于无效密钥要慢得多:因此,由于关键是您不知道密钥是否有效,因此给定一个未知的有效与无效概率,坚持key in dict)。

【讨论】:

  • 如果你能确保值是真实的。 var1 = d.get(k, None); if var1: ... 会更快吗?
  • 我想指出 try: except: 如果密钥无效,则性能最差。 1.07 µs > 132 ns。当密钥不存在时差异超过 800ns 和 20ns 支持 try/except 当密钥存在时,我不理解答案的“优于”。
  • @Bechma 我刚刚用 60k 键测试了这个并尝试了除了需要 1 秒而 k in d 需要 61 秒。
  • 记住,.has_key 不在 python3.8 或 python3.9 中(不是 %100 关于旧的 python3)
【解决方案2】:

假设您希望仅在设置了MyDict["key1"] 时才定义var1,显而易见的解决方案是var1 = MyDict.get("key1", default=some_sentinel_or_default_value)

wrt/ 表演,这主要取决于您是否希望“key1”在大多数情况下出现在您的 dict 中。如果是第一个,try/except 块可能会更快,否则它会更慢(try/except 块的设置成本很低,但在出现实际异常时成本很高)。

如果您真的很担心性能,我建议您使用timeit 模块在真实数据上测试各种选项

【讨论】:

  • 在这种情况下不是我想要的。我只想在键存在时触摸 var1(var1 可能会更早设置)每次键不存在时,您的方法都会用默认值覆盖 var1
  • 然后使用var1 = MyDict.get("key1", var1)
【解决方案3】:

你的这个方法非常快:

if 'key1' in MyDict:
       var1 = MyDict['key1']

假设您的字典中的项目和散列具有某些条件,这个should be on average O[1]

【讨论】:

    猜你喜欢
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    • 2017-08-26
    • 1970-01-01
    • 1970-01-01
    • 2013-01-04
    相关资源
    最近更新 更多