Python 中的 id() 函数

2017/1/21 posted in  Python 黑魔法

在 python 中,有个 id() 函数,是用来获得一个 Object 的 id 的,在文档中介绍也非常简单:

id(object)

Return the “ identity ” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

这是 python 为每个 Object 在运行时定制了一个唯一 id,但是需要注意的是,当两个 Object 当生命域不重叠的时候,可能会有相同的 id。

Object's Identity

对于任何一个 Object 来说,都有一个 id,如果多个变量指向了同一个静态常量,那么这几个变量讲拥有同样的 id。

>>> s1 = "abc"
>>> s2 = "abc"
>>> s1 == s2
True
>>> id(s1)
4390873208
>>> id(s2)
4390873208
>>> s1 is s2
True

如果两个不同的变量(常量),肯定将有不同的 id。

>>> id("abc")
4390873208
>>> id("abcd")
4391753216

is 比较

在 python 中,有两种常用的比较方式,一个是 == 比较,一个是 is 比较,前者是用来比较值是不是相等,后者是判断是不是属于同一个对象。其实,在 python 中,is 比较便是通过 id() 来实现的。当两个 Objec 拥有相同的 id 时,便会认为这是两个相同的对象。

因此,可以认为:object1 is object2 等价于 id(object1) == id(object2)

例外

今天在 v2ex 看到一个好玩的帖子(https://www.v2ex.com/t/336021 ),提到了 id([1]) == id([2]) 会返回 True

而我跑了一组数据,结果也是很有意思:

>>> id([1]) 
4391579520 
>>> id([2]) 
4391579520 
>>> a = [1] 
>>> b = [1] 
>>> id([1]) 
4391757944 
>>> id([2]) 
4391757944 
>>> id(a) 
4391579520 
>>> id(b) 
4391641672 
>>> id([1]) 
4391787072
>>> id([2]) 
4391787072  

因为在文档中已经提到了,两个不同生命域的对象可能会有相同的 id,因此出现这种情况也不例外,毕竟 [1][2],现在的确是两个不同的生命域的常量,因为这两个常量没有被任何变量引用,当使用结束之后,便会被回收掉,因此会出现两个不同的常量出现相同 id 的情况。

当给他们添加引用,会发现这个 id 就被确定到这个一个 [1] 常量上了,这是因为 这个 [1] 的生命域并没有结束(还被引用不能被回收),因此,新的 list object 不会再使用这个 id 而是换了新的 id。

2018.11.16 更新

今天又看到一种新的验证方式,定义如下类:

class WTF(object):
  def __init__(self): print("I")
  def __del__(self): print("D")

is 比较时,两个对象先创建再比较:

In [2]: WTF() is WTF()
I
I
D
D
Out[2]: False

id 比较时,当对象的 id 被获得之后,对象就会被注销,新对象恰好会分配在原内存空间,因此得到 True。

In [3]: id(WTF()) == id(WTF())
I
D
I
D
Out[3]: True