标识、相等性和别名

平时说两个变量标识的对象相等,会有两种情况表示:

  1. 两个变量标识的对象是同一个对象
  2. 两个变量表示的对象,其内部数值相等

这里提供一个例子来理解。

>>> a = [1, 2, 3, 4]
>>> b = a
>>> c = [1, 2, 3, 4]
>>> a == b == c
True
>>> a is b and b is a
True
>>> a is c
False
>>> id(a), id(b), id(c)
(2898513008896, 2898513008896, 2898513025664)

如上所示,a 和 b 变量标识的是同一个列表对象,可以通过 is 运算符或者 id 函数来查看两个变量是否标识同一个对象,通常来说使用 is 运算符更优雅。而,a 和 c 变量标识的对象仅仅是对象在比较时,比较的值相等。

元组的相对不可变性

一般来说,大家都知道元组是不可变的,但这个不可变仅仅是保持元组内元素不变,不论是数目还是元素值。

然而,由于元组和多数 Python 集合一样,保存的是对象的引用,因此,如果引用的对象是可变的,即便元组本身不可变,但元素标识的对象已经变了。而 strbytesarray.array 等单一类型序列是扁平的,它们保存的不是引用,而是在连续的内存中保存数据本身 (字符、字节和数字)。

让我想到了 Java 中的 Map 集合,在使用 Map 的时候,最好 key 是不可变的对象,至少保证 hash(key)是不变的,否则如果 key 对应的对象有变动,那么就大概率无法通过 get 操作获取到该 key 对应的 value 了。

>>> t1 = (1, 2, [30, 40])
>>> t2 = (1, 2, [30, 40])
>>> t1 == t2
True
>>> id(t1[-1])
4302515784
>>> t1[-1].append(99)
>>> t1
(1, 2, [30, 40, 99])
>>> id(t1[-1])
4302515784
>>> t1 == t2
False