python一切皆对象,命名皆引用
引用的理解
Python中一切皆对象,数值、字符串、函数、列表、类、文件等都是对象,加载到内存中时会给这些对象分配一些内存资源,可以通过id()函数来表示它们的内存地址。
Python中的赋值操作
python的一切都是围绕变量名和对象进行的。
Python中一切变量名都是引用,其赋值操作就是在给对象创建新的引用名,Python中普通的赋值操作就相当于C++中的引用操作。
比如代码:a = 1。
在C++中是表示将a这个变量所在内存的内容改为1。
在python中则表示让a指向对象1。
再比如:a += 1。
在C++中是表示将a这个变量所在内存的内容加上1。
在python中则表示让a指向2(加1后的值)这个对象。
再比如:a[0] = 100。
在C++中同样表示修改a[0]所在内存的内容。
在python中则表示让a[100]指向100这个对象,或给100这个对象命名为a[100]。
所以python中赋值的本质就是引用的指向变来变去。
对于赋值操作,可以分为两种情况:
变量名和变量名之间进行,这种情况称为间接引用。
变量名和对象之间进行,这种情况称为直接引用。
赋值后,新引用名所指向的对象有如下规则(对形参和实参都适用):
通过间接引用赋值,无论什么数据类型,都指向同一个内存地址,即同一个对象。
对于直接引用有:如果是可变数据类型(list、set、dict、可变tuple),会分别开辟内存,建立新的对象;对于不可变数据类型(含不可变tuple),则不会开辟新内存,比如常量等在内存中永远只有唯一的一份。
Python中的容器&深拷贝和浅拷贝
既然Python中一切命名都是引用,那么python容器的本质就是引用的集合。
对于容器类型的对象存在一个深拷贝和浅拷贝的问题
浅拷贝只涉及到创建新的父对象的引用名,不涉及任何创建新对象及创建新的子对象引用名的操作。
深拷贝会完全创建出一个全新的对象,新的引用名会指向新的对象。注意对于不可变类型是不会创建新对象的,新引用指向的仍是原始对象。
例子1:

b直接引用a,两者指向同一对象,操作a等于操作b
a == [1,2, 3, 4, ['a', 'b', 'c'], 5]
b == [1,2, 3, 4, ['a', 'b', 'c'], 5]
c是a的浅拷贝,父对象索引名都是新的引用名称,如a[4]和c[4]是两个不同的引用名,但a[4]和c[4]指向同一个对象,子对象引用a[0][0]和c[0][0]是同一个引用名。
c == [1,2, 3, 4, ['a', 'b', 'c']]
d=[1, 2, 3, 4, ['a', 'b']]
例子2:

将kvps['1']指向对象5,因为kvps['1']和theCopy['1']是两个不同的引用名,所以修改kvps['1']的指向并不影响theCopy['1']的指向,所以答案是6.
例子3:

间接引用,list['1']和list2['1']是同一个引用名,没有创建新的引用名,所以结果是10。
例子4:

浅拷贝创建了新的引用名,所以修改tmp['one']的指向不会影响原引用,结果是:
{'one': 1, 'two': 2, 'three': 3},{'one': 'abc', 'two': 2, 'three': 3}