我应该使用';具有_key()';或';在';关于Python dicts?

我应该使用';具有_key()';或';在';关于Python dicts?,python,dictionary,Python,Dictionary,我想知道什么更好: d = {'a': 1, 'b': 2} 'a' in d True 或: 在中,无疑更像蟒蛇 事实上。根据python: has_key()被弃用,取而代之的是 输入d 在中轻而易举地获胜,不仅在优雅方面(而且没有被弃用;-)而且在性能方面,例如: $ python -mtimeit -s'd=dict.fromkeys(range(99))' '12 in d' 10000000 loops, best of 3: 0.0983 usec per loop $ pyth

我想知道什么更好:

d = {'a': 1, 'b': 2}
'a' in d
True
或:


在中,
无疑更像蟒蛇

事实上。

根据python:

has_key()
被弃用,取而代之的是
输入d


中轻而易举地获胜,不仅在优雅方面(而且没有被弃用;-)而且在性能方面,例如:

$ python -mtimeit -s'd=dict.fromkeys(range(99))' '12 in d'
10000000 loops, best of 3: 0.0983 usec per loop
$ python -mtimeit -s'd=dict.fromkeys(range(99))' 'd.has_key(12)'
1000000 loops, best of 3: 0.21 usec per loop

虽然下面的观察并不总是正确的,但您会注意到,通常在Python中,更快的解决方案更优雅、更符合Python;这就是为什么
-mtimeit
如此有用的原因——它不仅仅是在这里和那里节省100纳秒

has\u key
是一种字典方法,但是
中的
将适用于任何集合,即使
\u contains\u\u
缺失,
中的
也将使用任何其他方法来迭代集合以找出答案。

使用
dict.has\u key()
如果(且仅当)在2.3之前的Python版本中,您的代码必须是可运行的(当引入了
key-in-dict
时)

有一个例子,其中
中的
实际上会扼杀您的性能

如果您在只实现
\uuuuu getitem\uuuuu
具有密钥()的O(1)容器上使用
,而不是
\uuuu contains\uuuuu
,您将把O(1)搜索变成O(N)搜索(因为
中的
通过
\uuuu getitem\uuuu
返回到线性搜索)

修复显然是微不足道的:

def __contains__(self, x):
    return self.has_key(x)
不推荐使用dict.has_key()的解决方案,请使用“in”-升华文本编辑器3

这里我举了一个名为“ages”的字典的例子-

ages = {}

# Add a couple of names to the dictionary
ages['Sue'] = 23

ages['Peter'] = 19

ages['Andrew'] = 78

ages['Karren'] = 45

# use of 'in' in if condition instead of function_name.has_key(key-name).
if 'Sue' in ages:

    print "Sue is in the dictionary. She is", ages['Sue'], "years old"

else:

    print "Sue is not in the dictionary"

以Adam Parkin的评论扩展Alex Martelli的性能测试

$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' 'd.has_key(12)'
Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py", line 301, in main
    x = t.timeit(number)
  File "/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py", line 178, in timeit
    timing = self.inner(it, self.timer)
  File "<timeit-src>", line 6, in inner
    d.has_key(12)
AttributeError: 'dict' object has no attribute 'has_key'

$ python2.7 -mtimeit -s'd=dict.fromkeys(range(  99))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0872 usec per loop

$ python2.7 -mtimeit -s'd=dict.fromkeys(range(1999))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0858 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(  99))' '12 in d'
10000000 loops, best of 3: 0.031 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d'
10000000 loops, best of 3: 0.033 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(  99))' '12 in d.keys()'
10000000 loops, best of 3: 0.115 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d.keys()'
10000000 loops, best of 3: 0.117 usec per loop
$python3.5-mtimeit-s'd=dict.fromkeys(范围(99))'d.has_key(12)'
回溯(最近一次呼叫最后一次):
文件“/usr/local/ceral/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py”,第301行,主文件
x=t.timeit(数字)
文件“/usr/local/ceral/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py”,第178行,在timeit中
定时=自内(it、自定时器)
文件“”,第6行,在内部
d、 有钥匙(12)
AttributeError:“dict”对象没有属性“has\u key”
$python2.7-mtimeit-s'd=dict.fromkeys(范围(99))'d.has_key(12)'
10000000个循环,最好3个:每个循环0.0872 usec
$python2.7-mtimeit-s'd=dict.fromkeys(range(1999))'d.has_key(12)'
10000000个循环,最好为3个:每个循环0.0858 usec
$python3.5-mtimeit-s'd=dict.fromkeys(范围(99))'12 in d'
10000000个循环,最佳3个:每个循环0.031 usec
$python3.5-mtimeit-s'd=dict.fromkeys(范围(1999))'12 in d'
10000000个循环,最好为3个:每个循环0.033 usec
$python3.5-mtimeit-s'd=dict.fromkeys(范围(99))'12 in d.keys()
10000000个循环,最好3个:每个循环0.115 usec
$python3.5-mtimeit-s'd=dict.fromkeys(范围(1999))'12 in d.keys()
10000000个循环,最好3个:每个循环0.117 usec

如果您有以下内容:

t.has_key(ew)
在Python 3.X及更高版本上运行时,请将其更改为以下内容:

key = ew
if key not in t


另外,在Python3中,要检查值而不是键中是否存在,请尝试>>>1 in d.values(),但要避免的一个半问题是确保您这样做:“在某些dict中设置键”而不是“在某些dict.keys()中设置键”。两者在语义上是等价的,但在性能方面后者要慢得多(O(n)vs O(1))。我看到人们认为“in dict.keys()”更明确,因此更好。@AdamParkin我在回答@AdamParkin的Python 3中演示了你的评论,
keys()
只是字典中的一个集合视图,而不是副本,因此
x in d.keys()
是O(1)。不过,
x在d
中更像是python。@AdamParkin有趣的是,我没看到这一点。我想这是因为
x in d.keys()
必须构造和销毁一个临时对象,并完成所需的内存分配,其中
x in d.keys()
只是在执行算术运算(计算散列)和查找。请注意,
d.keys()
的长度仅为此的10倍左右,但实际上还不长。我还没有检查过,但我仍然非常确定它只是O(1),并且在迭代器“x in xrange(90200)”上也能工作90…:这看起来是一个非常糟糕的主意:50个操作而不是2个。@Clément在Python3中,在
range
对象的
测试中执行
实际上是相当有效的。但是,我不太确定它在Python2
xrange
上的效率。@Clément不在Python3中;
\uu包含
可以简单地计算一个值是否在范围内。@AlexandreHuat您的计时包括每次创建一个新的
范围
实例的开销。使用一个预先存在的实例,“范围内的整数”测试在我的计时中大约快40%。多亏了这一点,使得验证“在某些情况下”事实上是O(1)更容易(试着将99增加到1999,你会发现运行时间大致相同)。
has_key
似乎是O(1)同样。2013年的WebSphere更新使用Jython 2.1作为其主要脚本语言。因此,不幸的是,在您注意到它五年后,这仍然是一件值得注意的事情。正确,但它已经得到了回答。欢迎来到Stackoveflow,感谢您的示例,但始终检查答案!@igorgue我不确定她是否投了反对票。她的回答是:她可能与已经回答的问题相似,但她提供了一个例子。这难道不足以成为如此精彩的统计数据的答案吗?有时候,隐含的可能比明确的好(至少在效率上)…谢谢你,@varun。我已经忘记了这个答案。我需要更频繁地进行这种测试。我经常阅读人们争论最佳方法的长文™ 但我几乎不记得这是多么容易得到证明。这个实验有一个缺陷,它混合了dict创建时间和键搜索时间。最好将两者分开,以测量仅在
key = ew
if key not in t