首先,保证为您提供与任何 dictkey in d.keys()
相同的值。key in d
d
对 a的in
操作dict
,或者dict_keys
你调用keys()
它返回的对象(在 3.x 中),不是O(N),而是 O(1)。
没有真正的“优化”。只是使用哈希是在__contains__
哈希表上实现的显而易见的方式,就像它是显而易见的实现方式一样__getitem__
。
你可能会问这是在哪里保证的。
好吧,事实并非如此。映射类型基本上定义dict
为collections.abc.Mapping
. 没有什么能阻止某人创建映射的哈希表实现,但仍提供 O(N) 搜索。但是做出如此糟糕的实现将是额外的工作,那么他们为什么要这样做呢?
如果您真的需要向自己证明这一点,您可以测试您关心的每个实现(使用分析器,或者使用带有自定义的某种类型__hash__
并__eq__
记录调用,或者......),或者阅读源代码。
在 2.x 中,您不想调用keys
,因为这会生成 alist
的键,而不是 a KeysView
。您可以使用iterkeys
,但这可能会生成一个迭代器或其他不是 O(1) 的东西。因此,只需将 dict 本身用作序列即可。
即使在 3.x 中,您也不想调用keys
,因为没有必要。迭代 a dict
,检查它的__contains__
,一般来说把它当作一个序列对待总是等价于对它的键做同样的事情,那么为什么要麻烦呢?(当然,构建琐碎的KeyView
,并通过它访问,将为您的运行时间增加几纳秒,并为您的程序增加一些击键。)
(不清楚使用序列操作在d.keys()
/d.iterkeys()
和d
2.x 中是等价的。除了性能问题之外,它们在每个 CPython、Jython、IronPython 和 PyPy 实现中都是等价的,但似乎并没有在任何地方说明它在 3.x 中的方式。没关系;只需使用key in d
.)
当我们这样做时,请注意:
if(dict[key] != None):
......不会工作。如果key
不在中dict
,这将提高KeyError
,而不是返回None
。
None
此外,您永远不应该检查==
or !=
; 总是使用is
.
您可以使用try
- 或者更简单地说 do来执行此操作if dict.get(key, None) is not None
。但同样,没有理由这样做。此外,这不会处理None
完全有效的项目的情况。如果是这种情况,您需要执行类似sentinel = object(); if dict.get(key, sentinel) is not sentinel:
.
所以,正确的写法是:
if key in d:
更一般地说,这是不正确的:
我知道“in”关键字通常是 O(n) (因为这只是转换为 python 迭代整个列表并比较每个元素
in
与大多数其他运算符一样,运算符只是对方法的调用(__contains__
或 C/Java/.NET/RPython 内置函数的等效项)。list
通过迭代列表并比较每个元素来实现它;dict
通过散列值并查找散列来实现它;blist.blist
通过遍历 B+Tree 来实现它;等等。所以,它可能是 O(n)、O(1)、O(log n) 或完全不同的东西。