写在前面
“Python 一切皆对象!”中的“对象”是“广义对象”,即万物皆对象!
本文所要讨论的“可变对象”和“不可变对象”中的“对象”是“狭义对象”,即在内存中真正存在的对象!
“不可变对象”和“可变对象”的区别
不可变对象:对象一旦在内存中生成后,它的值是不能被修改的,若要得到“不同值”的新对象,只能通过重新分配新内存创建新对象的方法!
可变对象:对象在内存中生成后,它的值可以被修改!若要得到“不同值”的新对象,既可以通过重新分配新内存创建新对象的方法,也可以在原对象的基础上直接修改值!(注意,可变对象并不意味着一定要在原对象上进行操作!)
下图清晰展示了两者的区别。对于不可变对象,执行a=1时,先生成一个对象1,然后将a指向该对象;执行a=2时,在新内存中生成一个对象2,然后将a指向这个新对象,如果原对象1没有其他变量指向它,那么将被销毁,释放内存!
对于可变对象,可在原值的基础上进行修改,无需生成新对象就可以得到新值。
不可变对象:int、字符串(str)、float、元组(tuple)、数值型(number)、空(None)
可变对象:列表(list)、字典(dict)、集合(set)
为什么要分可变和不可变对象?
廖雪峰博客:“为什么要设计str、None这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。”
★★必须要注意的问题
前面已经提到,对于不可变对象,是不能在原对象的基础上修改值的;对于可变对象,则可以在原对象的基础上修改值,但这并不意味着所有操作都要在原对象的基础上进行!见下例:
(情况1)在原对象上修改
>>>a = [1,2,3]
>>>print(id(a))
>>>a += [4]
>>>print(id(a))
>>>print(a)
36220232 #原对象地址
36220232 #依旧是原对象地址
[1, 2, 3, 4]
(情况2)在产生了新对象
a = [1,2,3]
print(id(a))
a = a + [4]
print(id(a))
print(a)
36244296 #原对象地址
36244232 #产生了新对象
[1, 2, 3, 4]
上面两种情况,唯一的差别是前者a += [4],后者a = a + [4],结果都得到了新的列表[1,2,3,4]。但两种情况的内存处理过程是完全不同的,前者在原对象上进行,而后者产生了新对象!
这两个例子的目的是为了说明,对于可变对象而言,有各种各样的方式可以对其进行操作(增加、删除、插入、排序、反向等等),这些操作有些会在原对象上进行,有些会新建一个新对象,编程时必须要搞清楚具体情况!