Python 为什么运算符为不可变对象提供不同的输出?

Python 为什么运算符为不可变对象提供不同的输出?,python,Python,代码“python”是“python”返回True。但是为什么(1,2,3)是(1,2,3)返回False?即使两者都是不可变对象,is操作符的计算方式也不同。为什么?如果两个操作数引用同一对象,则返回True。解释器可以对不可变的对象使用interning,但不能保证这样做 运算符和不测试对象标识:当且仅当x和y是同一对象时,x为y为真。x不是y,产生反真值 您可以将标识视为对象在内存中的地址。所以对于具有相同索引的2元组,我们有不同的地址在本例中,基于解释器和解释器中的上述内容,相等字符串指

代码
“python”是“python”
返回
True
。但是为什么
(1,2,3)是(1,2,3)
返回
False
?即使两者都是不可变对象,
is
操作符的计算方式也不同。为什么?

如果两个操作数引用同一对象,则返回True。解释器可以对不可变的对象使用interning,但不能保证这样做

运算符不测试对象标识:当且仅当x和y是同一对象时,x为y为真。x不是y,产生反真值

您可以将标识视为对象在内存中的地址。所以对于具有相同索引的2元组,我们有不同的地址在本例中,基于解释器和解释器中的上述内容,相等字符串指向一个内存地址

要更好地理解,请参阅以下演示:

>>> a=(0,1)
>>> b=a
>>> a is b
True
>>> c=(0,1)
>>> a is c
False

您的第一个示例是
True
的唯一原因是,从源代码加载时,字符串文本会被插入(我认为这甚至只适用于单个文件中的字符串)


除了字符串文字外,几乎所有情况下,在不同时间创建的对象都会有不同的ID。

如果有疑问,
X是Y
检查
X
Y
。它不会检查两个对象是否相等

现在谈谈你的问题:

对于给定的文本
A
是否返回
True
False
,您通常不应该有任何期望

我们非常清楚CPython在内部是如何工作的,所以我们知道为什么每个特定的案例都会以这种方式工作。也就是说,除了在某些真正特殊的情况下,最好将其视为一个实现细节。在不同的Python解释器中,或者在不同版本的CPython中,它的行为可能会有所不同


当然,这并不意味着
没有用处。是的,只是不在本例中。

与不变性无关。第一个示例是您可以称之为代码块中常量的局部内部(第1124行;本例中的dict用于构建
常数
)。这与全局字符串和整数的内部处理是分开的,即
'1 2 3'
不是内部处理,但
'1 2 3'是'1 2 3'
。同样地,
1234567是1234567
,尽管CPython在全球范围内的实习人数最多只有256人。另外,
1.23456是1.23456
@eryksun你应该把它写下来作为一个答案,元组的大小写是不同的
BUILD\u TUPLE
在运行时创建一个不一定是常量的元组。这就是说,确实将常量元组添加到
co_consts
中。它只是不能消除重复。例如,
compile(“(1,2,3)是(1,2,3)”,“exec”).co_consts==(1,2,3,None,(1,2,3),(1,2,3))
。第一个过程有两个
BUILD\u TUPLE
ops。优化过程将它们替换为
LOAD_CONST
ops,这些ops从
co_CONST
+1个好答案加载元组。您可能会继续解释,它对可变对象和不可变对象都是一样的,因为它不能回答这个问题。您的演示与OP的代码不同。元组和字符串都是不可变的,为什么它们的行为会不同呢?谢谢大家的关注,我编辑了答案!请不要将Python对象标识视为内存中的地址。这只适用于CPython,因为CPython对象是堆分配的,永远不会在内存中移动。