我习惯在 Python 中看到
if obj is None:
,最近也遇到了 if obj is ():
。由于元组是不可变的,这听起来像是 Python 解释器中合理的内部优化,让空元组成为单例,因此允许使用 is
而不是要求 ==
。但这在某个地方得到保证吗?从哪个版本的解释器开始?
[编辑]这个问题很重要,因为如果 () 不是单例,并且有一种方法可以生成具有不同地址的空元组,那么使用
is {}
是一个错误。如果仅从 Python 2.x 开始保证 x > 0,那么如果您需要确保代码的向后兼容性,那么了解 x 的值就很重要。同样重要的是要知道在使用 pypy / jython / ironpython 时这是否会破坏你的代码......
这是当前版本的 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
不过,如果这种效率差异至关重要,我认为这将表明存在设计问题。
让我们使用 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 中)。
对于
""
空字符串变量也有相同的行为。
这与优化无关。这是关于对象比较。 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