python 确定字典中是否存在键[重复]

x4shl7ld  于 2023-01-16  发布在  Python
关注(0)|答案(4)|浏览(137)
    • 此问题在此处已有答案**:

Check if a given key already exists in a dictionary(16个答案)
15小时前关门了。
我有一个Python字典,比如mydict = {'name':'abc','city':'xyz','country','def'}
我应该如何检查一个键是否在字典中?我已经知道这些方法:
if mydict.has_key('name'):
if 'name' in mydict:

ki1q1bka

ki1q1bka1#

if 'name' in mydict:

是首选的Python版本,不鼓励使用has_key(),这个方法在Python 3中已经被删除了。

eqqqjvef

eqqqjvef2#

和martineau的回答一样,最好的解决方案通常是不检查。

if x in d:
    foo = d[x]
else:
    foo = bar

通常被写入

foo = d.get(x, bar)

更短更直接地表达你的意思。
另一个常见的例子是

if x not in d:
    d[x] = []

d[x].append(foo)

可以重写

d.setdefault(x, []).append(foo)

或者通过使用collections.defaultdict(list)作为d并写入

d[x].append(foo)
vdgimpew

vdgimpew3#

在字节码方面,in保存了一个LOAD_ATTR,并用一个COMPARE_OP替换了一个CALL_FUNCTION

>>> dis.dis(indict)
  2           0 LOAD_GLOBAL              0 (name)
              3 LOAD_GLOBAL              1 (d)
              6 COMPARE_OP               6 (in)
              9 POP_TOP             

>>> dis.dis(haskey)
  2           0 LOAD_GLOBAL              0 (d)
              3 LOAD_ATTR                1 (haskey)
              6 LOAD_GLOBAL              2 (name)
              9 CALL_FUNCTION            1
             12 POP_TOP

我的感觉是in的可读性要强得多,在我能想到的每一种情况下都是首选。
就性能而言,计时反映了操作码

$ python -mtimeit -s'd = dict((i, i) for i in range(10000))' "'foo' in d"
 10000000 loops, best of 3: 0.11 usec per loop

$ python -mtimeit -s'd = dict((i, i) for i in range(10000))' "d.has_key('foo')"
  1000000 loops, best of 3: 0.205 usec per loop

in几乎快了两倍。

nwlls2ji

nwlls2ji4#

我的回答是“都不是”。
我相信最“Python”的做事方式是不事先检查键是否在字典中,而是只编写假设它在那里的代码,并捕捉任何因为它不在而引发的KeyError。
这通常是通过将代码封装在try...except子句中来完成的,这是一个众所周知的习惯用法,通常表示为“请求原谅比请求许可容易”或缩写为EAFP,这基本上意味着最好尝试一些东西并捕获错误,而不是在做任何事情之前确保一切正常。当你可以优雅地处理异常而不是试图避免它们时,你就不需要验证了吗?因为如果键不存在的可能性很低(或者不管有什么先决条件),那么它通常更具可读性,代码也会更快。
当然,这并不适用于所有情况,也不是每个人都同意这种哲学,所以你需要根据具体情况自己决定。毫不奇怪,与此相反的是LBYL,意思是“三思而后行”。
举个简单的例子:

if 'name' in dct:
    value = dct['name'] * 3
else:
    logerror('"%s" not found in dictionary, using default' % name)
    value = 42

对比

try:
    value = dct['name'] * 3
except KeyError:
    logerror('"%s" not found in dictionary, using default' % name)
    value = 42

虽然在这种情况下,它的代码量几乎完全相同,但第二种方法不需要先花时间检查,而且可能会稍微快一些(尝试......尽管block并不是完全免费的,所以在这里可能不会有太大的区别)。
一般来说,提前测试通常会涉及更多的内容,不做测试可以节省大量成本。也就是说,基于其他答案中所述的原因,if 'name' in dict:更好。
如果您对该主题感兴趣,请阅读标题为“EAFP vs LBYL(回复:到目前为止有点失望)”可能比我在这里更好地解释了这两种方法之间的区别。Alex Martelli的书Python in a Nutshell, 2nd Ed在关于异常的第6章中也有关于这两种方法的很好的讨论,书名为Error-Checking Strategies。(我看到现在有一个更新的3rd edition,发布于2017年,它涵盖了Python 2.7和Python 3.x)。

相关问题