python中检查字典中键的正确方法

python中检查字典中键的正确方法,python,dictionary,Python,Dictionary,所以我一直在想。假设d是一本字典……检查字典中是否有键的正确(更像Python)方法是什么: k in d or k in d.keys() 或者别的什么???总是使用 k in d 这是一个O(1)恒定时间操作 另一种选择是d.keys()中的k,在Python2中是一个O(N)线性时间操作,在Python3中充其量是一个不必要的方法调用。不要用它 d.keys()是三个额外的步骤,一个属性查找、一个函数调用和一个新对象的创建。在Python2中,它是所有键的列表对象(需要首先列出这些

所以我一直在想。假设d是一本字典……检查字典中是否有键的正确(更像Python)方法是什么:

k in d
  or
k in d.keys()
或者别的什么???

总是使用

k in d
这是一个O(1)恒定时间操作

另一种选择是d.keys()中的
k
,在Python2中是一个O(N)线性时间操作,在Python3中充其量是一个不必要的方法调用。不要用它


d.keys()
是三个额外的步骤,一个属性查找、一个函数调用和一个新对象的创建。在Python2中,它是所有键的列表对象(需要首先列出这些键),在Python3中,它是字典视图。仅在测试是否存在密钥时,这两者都是完全冗余的。在Python2中,针对list对象的包容测试需要扫描所有元素,直到找到匹配项。

k in d
无疑是最好的继续测试方法,因为它将更快O(1),因为它将使用字典的哈希,而不是线性搜索,在这种情况下,当您调用keys时就可以了


还有一种方法可以使用
dict.has_key(key)
。虽然Python3.0中不推荐使用“has_key”

d中的k是有效的。当您执行d.keys()时,您将获得所有键作为列表,然后在列表中进行检查。因此,它必须先形成一个列表,根据列表的大小,性能会变慢。有更好的方法来检查所用的时间,但这应该有助于您看到差异:

d={}
for i in range(1000000):
    d[i]=i*2

start_time = time.time()
if 2 in d:
    print "yes"
print("-key in d -- %s seconds ---" % (time.time() - start_time))

start_time = time.time()
if 2 in d.keys():
    print "yes"
print("--key in d.keys()- %s seconds ---" % (time.time() - start_time))
我的电脑上的输出:

yes
-key in d -- 0.0 seconds ---
yes
--key in d.keys()- 0.0169999599457 seconds ---

出于好奇,我刚刚在Python3中试用了它,实际上,与Python2相比,这两种操作现在看起来都像是O(1)操作

import random
import string

def rand_string(length):
    """ Generates a random string of numbers, lower- and uppercase chars. """
    return ''.join(random.choice(
            string.ascii_lowercase + string.ascii_uppercase + string.digits)
                   for i in range(length)
            )

big_dict = {rand_string(20):rand_string(20) for i in range(10000)}

比较 对于记录,使用try/except进行比较(感谢
timeit
模块)

代码 结果 以下是不同dict长度和是否输入dict的一些计时结果(以秒为单位):

简短的格言:

lend = 200
idx = 0

>> 0.18031001091   # k in d
>> 0.216886997223  # try/except
>> 1.06729197502   # k in d.keys()
lend = 200
idx = 201

>> 0.178912878036  # k in d
>> 1.32136297226   # try/except
>> 4.93310189247   # k in d.keys()
简而言之:

lend = 200
idx = 0

>> 0.18031001091   # k in d
>> 0.216886997223  # try/except
>> 1.06729197502   # k in d.keys()
lend = 200
idx = 201

>> 0.178912878036  # k in d
>> 1.32136297226   # try/except
>> 4.93310189247   # k in d.keys()
长篇格言:

lend = 20000
idx = 1

>> 0.178980827332  # k in d
>> 0.22277712822   # try/except
>> 105.207716942   # k in d.keys()
出自长篇大论:

lend = 20000
idx = 20001

>> 0.184767007828  # k in d
>> 1.38200902939   # try/except
>> 490.606647968   # k in d.keys()
结论 当键在dict中时,try/except方法比d中的
k慢一点。但是,如果键不在dict中,try/except的性能较差,但优于d.keys()中的
k


鉴于性能和可读性,
k in d
是首选。

任何一个都可以。我通常是第一个。@Cyber:不,在Python 2中不是。d中的
k
是一种解决方法,您可以直接使用d[k]并捕获异常(如果缺少键很少见)或d.get(k,默认值),以防不存在。那么你就不需要做检查了。
d.get(k)
的问题是当
d[k]=None时,那么
k在d!=(d.get(k)不是None)
dict.has_key()
已被弃用。它需要一个属性查找和一个函数调用(2条指令),而在
@MartijnPieters中使用
进行成员资格测试则需要一条字节码指令:-是的,我已经更新了!它在Python 2中被弃用,在Python 3中被完全删除。@MartijnPieters:-真的@帕德雷坎宁厄姆:-更新了。谢谢你的建议。如果你想使用时间代码,请使用timeit