Python “巨蟒”;是";语句和元组

Python “巨蟒”;是";语句和元组,python,comparison,tuples,Python,Comparison,Tuples,为什么()是()真的,(0,)是(0,)是假的 我以为他们会是同一个物体。然而,我显然遗漏了一些东西 是检验身份,而不是平等。这意味着Python只是比较对象所在的内存地址。它基本上回答了“同一个对象有两个名称吗?” 通常Python会将每个元组写入不同的内存位置, 大多数情况下只对字符串文本执行。is测试语句的两侧是否共享相同的内存地址。它基本上是id(a)=id(b) 由于()发生得相当频繁,Python解释器实际上将其视为一个单例(就像0到255之间的整数、空字符串、空列表等)。当将(0,

为什么
()是()
真的,
(0,)是(0,)
是假的


我以为他们会是同一个物体。然而,我显然遗漏了一些东西

是检验身份,而不是平等。这意味着Python只是比较对象所在的内存地址。它基本上回答了“同一个对象有两个名称吗?”

通常Python会将每个元组写入不同的内存位置,

大多数情况下只对字符串文本执行。

is
测试语句的两侧是否共享相同的内存地址。它基本上是id(a)=id(b)


由于
()
发生得相当频繁,Python解释器实际上将其视为一个单例(就像0到255之间的整数、空字符串、空列表等)。当将
(0,)
(0,)
与解释器进行比较时,它们实际上是内存中不同的变量。如果它们是可变的,你可以修改第一个,而第二个不会改变,因此它们是不同的(
a不是b
)。

正如Dougal在他的评论中所说,
is
测试你正在比较的两个东西在内存中的相同位置。对于数字、字符串、布尔值和空元组等对象,Python默认情况下重用对象(interning),因此
is
通常会产生与
=
相同的行为。这也意味着您可以通过比较内存指针而不是字符串等更复杂的数据类型来获得一些性能增益

对于其他事物,例如您案例中的元组(即使它们是不可变的),或者列表,甚至是空列表
[]
,Python将在不同的内存位置创建一个新对象,并且
is
的工作方式与
=
不同


如果您试图按值比较两个元组,
=
将是更好的比较。

is
表示它们在内存中是相同的对象。显然,CPython只有一个空元组的副本,但为包含内容的元组创建了新的副本。似乎他们可以使用内存中相同的位置来创建相同的元组,因为它们是不可变的。然而,它们不这样做可能有一个原因。@RectangleTangle,您需要一种有效的方法来定位相同的元组。想一想,从技术上来说,插入元组是可能的,但是实现比插入字符串更复杂,因为元组可以容纳可变类型。让Python创建多个相同的字符串和数字版本是相当容易的。Python不承诺对它们进行实习,它可能只是选择这样做以节省内存,因此
is
的行为对于这些对象来说变得不可预测。因此,虽然使用
is
比较字符串可能更有效,但它有可能给代码带来微妙的错误,除非您仅在您知道程序行为不会遇到此问题的受控位置使用它。一般来说,不可变对象应该总是与
=
相比较,而不是与
is
相比较@Ben,
a is b或a==b
也可以吗?不过,第二次比较可能会否定所获得的性能。@RectangleTangle视情况而定;如果
a
通常不是
b
,那么你大部分时间就是在浪费工作。使用多个Python级别的操作来保存一个短的C循环听起来也不太可能是一个巨大的回报,除非将一个巨大的字符串与它本身进行比较是很常见的。当我测试的是语义平等时,我只使用
=
,当我测试的是语义身份时,我只使用
=
。理论上,如果我发现字符串比较是程序中的一个重要瓶颈,而且速度太慢,那么我可以回去替换其中的一些,但这从未发生在我身上。@Ben你是对的,我应该对我关于获得性能提升的陈述进行限定-你只能真正依赖它来处理布尔、无和空元组。对于字符串和数字,行为可能定义不清。实际上,我根本不应该提及性能增益:它可能会诱使人们过早地进行优化。根据本的实践,我们应该总是从最清晰的语义开始;它们是可变的,所以您希望每次出现
[]
都创建一个新列表!另外,在这样的临时对象上使用
id
时要小心;在我的系统上,在REPL中输入
(id([]),id([])
,会给出
(48511432L,48511432L)
,但这并不意味着它们是同一个对象;只是第一个列表在
id
ed之后被作为垃圾丢弃,然后第二个被分配到内存中这个方便的空列表大小的洞中,这个洞刚刚被释放<代码>id值可能没有意义,除非您确保对象的寿命长于
id
值。@Ben,将列表分配给名称(这将持续整个比较过程)将消除潜在的问题,对吗?@Ben表达式
[]is[]
是否存在相同的临时对象问题(也就是说,仅仅因为内存被重用,它就可以评估为
True
)?我猜不是,但不确定如何防止这种情况发生。@max Correct,
is
测试没有问题。原因是
is
直接测试对象,这意味着它们必须同时处于活动状态,以便您将它们传递给
is
,因此,如果它们处于活动状态,它们不会意外地拥有相同的内存地址不同的对象。比较
id
结果会将事情分为多个阶段,这样就有可能在您获取
id
后但在分配第二个对象之前释放第一个对象,这就有可能在同一地址分配两个不同的对象,并且具有相同的 id。
>>> print id(()), id(())
30085168 30085168
>>> print id((0,)), id((0,))
38560624 38676432
>>>