Python 不可变类型 ID 和 if 语句

Python immutable type ids and the is statment

我认为下面的所有内容都会评估为 False。有人可以解释发生了什么吗?不可变构造函数不会创建新对象(和新 ID)吗?元组如何具有相同的id并且是不同的对象?

print((1,) is (1,))
print(id(1,) == id(1,))
print('a' is 'a')
print(id('a') == id('a'))

结果:

False
True
True
True

您使用元组的每个实例构造一个不可变类型的新实例。元组的值不能改变,但它们是不同的(虽然相等)实例。

你的第二行不正确。您正在将 1 传递给 id。 (Python 允许在参数列表中使用尾随逗号。)

print((1,) is (1,))
print(id((1,)) == id((1,)))
print('a' is 'a')
print(id('a') == id('a'))

哪些是

False
False
True
True

所以 idis 的结果匹配。


请注意,is/id 的结果可能因实施而异。

例如,在 CPython 2.7 中,2 * 2 is 42 * 200 is not 400。对于低整数值,CPython 使用相同的内存地址(这是 CPython 中 id 的结果)。同样,这因实施而异。

您可能会在 Python、Java 和其他对象中使用不可变对象看到 interning 的结果。

PEP237 状态:

  • 具有小值的短整数(通常在 -1 到 99 之间 inclusive) 是 "interned" -- 只要结果有这样的值, 返回具有相同值的现有 short int。这是 没有为具有相同值的长整数完成。这个区别 会保持。 (由于不能保证这次实习,是 这是否是语义差异值得商榷——但代码 可能存在使用 'is' 比较短整数和 正好因为这次实习工作。这样的代码可能会失败 如果与长整数一起使用。)

示例:

>>> x=7
>>> y=10-3
>>> z=int('7')
>>> all(7 is e for e in [x,y,z])
True
>>> map(id, [x,y,z])
[140410571769784, 140410571769784, 140410571769784]

字符串:

>>> s1='abc'
>>> s2='abc'
>>> s1 is s2
True
>>> id(s1)
4378429560
>>> id(s2)
4378429560

您不能依赖不可变对象的实例作为该对象的唯一标签。它是一个实现细节,可能因版本和实现而异。

print((1,) is (1,))
print(id(1,) == id(1,))
print('a' is 'a')
print(id('a') == id('a'))

1- 首先评估为 false 因为 2 个元组是不同的对象

2- 它的计算结果为真,因为 id(1,) 不将 1, 识别为元组,而只是将其识别为 1,并且当您有小整数或字符串时,python 执行优化将 2 个名称引用到相同的 id,因此它不必分配 2 个不同的空间。如果你有 id((1,)) 那将是错误的,因为它会把它识别为一个元组

3 和 4 - 它们为真,原因与 2 为真相同