python对象的引用特征和可变性

来源:互联网 发布:淘宝支出统计 编辑:程序博客网 时间:2024/05/19 20:39

对象的身份,相等性和别名

先看一个例子:

>>> a = [1,2,3,4]>>> b = a>>> b is aTrue>>> id(a),id(b)(58065824, 58065824)>>> a.append(5)>>> a[1, 2, 3, 4, 5]>>> b[1, 2, 3, 4, 5]>>> 

(1)这里的b就是a的一个别名(alias)

(2)所以is返回true,id()函数对a和b返回的值也是相同的

(3)针对a的修改也同时修改了b

继续:

>>> c = [1,2,3,4,5]>>> c == aTrue>>> c is aFalse>>> 

(1)这里的c的值与a相等,所以==返回True

(2)但是c不是a的别名,它们的id不同

它们在内存中的数据模型如下图所示:

这里写图片描述

为什么会有上面的不同呢?

其实,在python手册中的数据模型解释中有这么一段话:

Every object has an identity, a type and a value. An object’s identity never changes once
it has been created; you may think of it as the object’s address in memory. The is operator
compares the identity of two objects; the id() function returns an integer representing its identity.

主要意思:

(1) 每个对象都有一个唯一的id,(CPython中id就是对象在内存中的地址),且在创建的时候确定,以后不再改变;

(2) is比较是比较两个对象的id;

(3) id()函数返回的是一个整形的对象id;

上面的例子中c是一个新创建的对象,虽然内容和a一样,但是id是不同的,所以is返回的是False,而b仅仅是a的一个别名,相当于C++中的引用,b和a在内存中的地址是一样的,是同一个对象,所以is返回True。至于c和a的==比较返回True,下面会继续解释。

何时选择is,何时用==

==操作符比较的是对象的内容,而is比较的是对象的id。

==操作符在比较的时候其实是调用了对象的.eq()函数, a == b其实是调用了a.eq(b)的结果。这也就是为什么is会比==快的原因。

元组(tuple) 不变性的一个陷阱

元组(tuple)和其他容器类型一样,存放的都是对象的引用,元组是不可改变的,但是如果它的元素是可变类型的,那么它还是可以被改变的。下面的例子可以说明:

>>> t1= (1,2,[3,4])>>> t1[-1].append(5)>>> t1(1, 2, [3, 4, 5])>>>

通过Python Online Tutor可以看到这里的内存数据结构如下图:

这里写图片描述

这里写图片描述

在看如下操作,
t1[2] += [6,7]
这个会发生什么呢?

>>> t1[2] += [6,7]Traceback (most recent call last):  File "<pyshell#25>", line 1, in <module>    t1[2] += [6,7]TypeError: 'tuple' object does not support item assignment>>> t1(1, 2, [3, 4, 5, 6, 7])

可以看到,抛出了异常,这很好理解,tuple是不可变的,针对tuple元素的赋值会抛出TypeError异常。但是这里的t1中的列表元素还是变了,再看下执行前后的状态。

这里写图片描述

这里写图片描述

0 0