Python 中的两个整数具有相同的 id,但列表或元组则没有
- 2025-02-13 08:35:00
- admin 原创
- 54
问题描述:
Python 中的两个整数有相同的id
:
a = 10
b = 10
a is b
>>> True
如果我取两个list
s:
a = [1, 2, 3]
b = [1, 2, 3]
a is b
>>> False
根据此链接, Senderle 回答说不可变对象引用具有相同的 id,而可变对象(如列表)具有不同的 id。
因此现在根据他的回答,元组应该具有相同的 ID - 含义:
a = (1, 2, 3)
b = (1, 2, 3)
a is b
>>> False
理想情况下,由于元组是不可变的,它应该返回True
,但它正在返回False
!
怎么解释呢?
解决方案 1:
不可变对象不具有相同的id
,事实上,对于您单独定义的任何类型的对象来说,情况并非如此。一般来说,每次在 Python 中定义一个对象时,您都会创建一个具有新标识的新对象。但是,出于优化的考虑(大多数情况下),对于小整数(介于 -5 和 256 之间)和内部字符串有一些例外,它们具有特殊长度——通常少于 20 个字符—— *它们是单例并且具有相同的id
(实际上是一个具有多个指针的对象)。您可以像下面这样检查:
>>> 30 is (20 + 10)
True
>>> 300 is (200 + 100)
False
>>> 'aa' * 2 is 'a' * 4
True
>>> 'aa' * 20 is 'a' * 40
False
对于自定义对象:
>>> class A:
... pass
...
>>> A() is A() # Every time you create an instance you'll have a new instance with new identity
False
还要注意,is
运算符将检查对象的身份,而不是值。如果要检查值,则应使用==
:
>>> 300 == 3*100
True
而且由于对于元组或任何可变类型没有这样的优化或实习规则,如果定义两个相同的元组,无论大小,它们都会获得自己的身份,因此是不同的对象:
>>> a = (1,)
>>> b = (1,)
>>>
>>> a is b
False
还值得一提的是,“单例整数”和“内部字符串”的规则即使已经在迭代器中定义,也是正确的。
>>> a = (100, 700, 400)
>>>
>>> b = (100, 700, 400)
>>>
>>> a[0] is b[0]
True
>>> a[1] is b[1]
False
一篇关于此问题的优秀且详细的文章:http://guilload.com/python-string-interning/
解决方案 2:
不可变的!=
同一对象。*
不可变对象只是一个状态无法改变的对象;仅此而已。当创建一个新对象时,将为其分配一个新的地址。因此,检查地址是否相等is
将返回False
。
事实上,1 is 1
或"a" is "a"
返回True
是由于Python 执行的整数缓存和字符串驻留,所以不要让它混淆你;它与所讨论的对象是可变/不可变的无关。
*空的不可变对象确实引用同一个对象,并且它们的is
性质确实返回 true,但这是一个特殊的实现特定情况。
解决方案 3:
看一下这段代码:
>>> a = (1, 2, 3)
>>> b = (1, 2, 3)
>>> c = a
>>> id(a)
178153080L
>>> id(b)
178098040L
>>> id(c)
178153080L
为了弄清楚为什么a is c
被评估为True
而a is b
得出我强烈建议您在在线 Python 教程False
中逐步运行上面的代码片段。内存中对象的图形表示将为您提供对这个问题的更深入了解(我附上了一张截图)。
解决方案 4:
根据文档,不可变变量可能具有相同的 ID,但不能保证它们确实如此。可变变量始终具有不同的 ID。
https://docs.python.org/3/reference/datamodel.html#objects-values-and-types
类型几乎影响对象行为的所有方面。甚至对象身份的重要性在某种意义上也受到影响:对于不可变类型,计算新值的操作实际上可能返回对具有相同类型和值的任何现有对象的引用,而对于可变对象,这是不允许的。
在以前的 Python 版本中,元组被分配了不同的 ID。(3.7 之前)
从 Python 3.7+ 开始,分配了相同元组的两个变量可能具有相同的 id:
>>>a = (1, 2, 3)
>>>b = (1, 2, 3)
>>>a is b
True
256 以上的整数也有不同的 ID:
>>>a = 123
>>>b = 123
>>>a is b
True
>>>
>>>a = 257
>>>b = 257
>>>a is b
False
解决方案 5:
检查下面的代码。当我们将 tupils a和b的旧值重新赋值时,它们会保留其旧的引用(ID)。(但是,列表不会出现这种情况,因为它们是可变的)
最初a和b具有相同的值 ( (1,2) ),但它们具有不同的 ID。在更改它们的值之后,当我们将值 (1,2) 重新分配给a和b时,它们现在引用的是它们自己的相同 ID(分别为 88264264 和 88283400)。
>>> a = (1,2)
>>> b = (1,2)
>>> a , b
((1, 2), (1, 2))
>>> id(a)
88264264
>>> id(b)
88283400
>>> a = (3,4)
>>> b = (3,4)
>>> id(a)
88280008
>>> id(b)
88264328
>>> a = (1,2)
>>> b = (1,2)
>>> id(a)
88264264
>>> id(b)
88283400
>>> a , b
((1, 2), (1, 2))
>>> id(a) , id(b)
(88264264, 88283400)
>>>
**阅读本文后,请查看链接为什么元组在分配相同的值时不会获得相同的 ID?。
这里还讨论了另一种情况。