使用 Python 2.x 中的“is”运算符将对象与空元组进行比较

问题描述 投票:0回答:4

我习惯在 Python 中看到

if obj is None:
,最近也遇到了
if obj is ():
。由于元组是不可变的,这听起来像是 Python 解释器中合理的内部优化,让空元组成为单例,因此允许使用
is
而不是要求
==
。但这在某个地方得到保证吗?从哪个版本的解释器开始?

[编辑]这个问题很重要,因为如果 () 不是单例,并且有一种方法可以生成具有不同地址的空元组,那么使用

is {}
是一个错误。如果仅从 Python 2.x 开始保证 x > 0,那么如果您需要确保代码的向后兼容性,那么了解 x 的值就很重要。同样重要的是要知道在使用 pypy / jython / ironpython 时这是否会破坏你的代码......

python
4个回答
13
投票

来自 Python 2 docs 和 Python 3 docs

...空元组的两次出现可能会也可能不会产生相同的对象。

换句话说,你不能指望

() is ()
评估为true。


1
投票

这是当前版本的 CPython 的无保证实现细节,因此您不一定能够在其他 Python 实现中依赖它,包括 Jython、IronPython、PyPy 以及潜在的未来版本的 CPython。

与大列表相比,在我的系统上使用

is
似乎快了约 0.04 μs:

$ python -m timeit -s "x = range(10000)" "x is ()"
10000000 loops, best of 3: 0.0401 usec per loop

$ python -m timeit -s "x = range(10000)" "x == ()"
10000000 loops, best of 3: 0.0844 usec per loop

当然,如果您使用自定义

__eq__()
方法与某些内容进行比较,情况可能会更糟:

$ python -m timeit -s $'import time\nclass X(object):\n    def __eq__(self, other): return time.sleep(1)\nx = X()' "x == ()"
10 loops, best of 3: 1e+03 msec per loop

不过,如果这种效率差异至关重要,我认为这将表明存在设计问题。


0
投票

让我们使用 id() 方法来获取 () 的内部 id :

>>> id(())
140180995895376
>>> empty_tuple = ()
>>> id(empty_tuple)
140180995895376        # same as the id of ()
>>> from copy import copy
>>> id(copy(empty_tuple))
140180995895376        # still the same as the id of ()

看起来 () 在 python 中有效地存储为单例(至少在 python>2.6 中)。

对于

""
空字符串变量也有相同的行为。


-1
投票

这与优化无关。这是关于对象比较。 Python“is”用于测试对象同一性,然后比较空元组“()”不需要使用“==”运算符。事实上,Python中任何东西都可以用“is”来比喻。

>>> obj = ()
>>> obj is ()
True
>>> isinstance(obj, tuple)
True
>>> obj is tuple
False
>>> type(obj) is tuple
True
>>> type(())
<type 'tuple'>
>>> type(tuple)
<type 'type'>
>>> tuple == type(()) # value comparison with ==
True

任何其他值都相同:

>>> 333 is int
False
>>> type(333) is int
True
>>> isinstance(333, int)
True
© www.soinside.com 2019 - 2024. All rights reserved.