1.首先是元组不可变,指的并不是元组内容不可变,是指元组中各项元素的内存地址不可变。
例如 a=(1,2,3,[4,5]) ; a[-1].append(6);
结果: a=(1,2,3,[4,5,6])
实际上 id(a[-1])并没有改变
这也就是所说的“元组不可变”。
2.is 与 ==
is比较的是两个变量的地址是否相同,具有更快的比较效率(但不同地址的元素也可能值相同)
==就是比较2个变量的值是否相等
同时,python中有个特性:-25~256的整数,是预先缓存好的(但是好像3.11中,所有的整数都是这样)
即a=1,b=1 实际上他俩的id是相同的,直接指向1原先缓存的地址。
先说结论:在数据的独立性方面---直接赋值<浅拷贝<深拷贝
3.直接赋值
其实就是对象的引用(别名)
a=xxxx
b=a
b就是a的别名, a,b的地址是完全相同的,因此a怎么变,b也跟着变;b怎么变,a也跟着变。
就是说,a,b是一回事
4.浅拷贝
拷贝父对象,不会拷贝对象的内部的子对象。
例如:
a=[1,2,3,4,[5,6]]
b=a.copy()
a.append(123)
print(a)
print(b)
输出:
[1, 2, 3, 4, [5, 6], 123]
[1, 2, 3, 4, [5, 6]]
此时a,b已经是不同的地址了,b拷贝了a的内容(父对象),但a中的可变内容([5,6]), a,b是共同指向的。 这就是所说的:只拷贝了父对象,没有拷贝内部的子对象
所以,a,b从整体上是不同的,但内部的可变对象---[5,6]仍是共享的(从效果上看是共享效果,实际上地址也不同)
例如:
a=[1,2,3,4,[5,6]]
b=a.copy()
a[-1].append(123)
print(a)
print(b)
输出:
[1, 2, 3, 4, [5, 6, 123]]
[1, 2, 3, 4, [5, 6, 123]]
这就是浅拷贝,从整体上变的时候,a,b是独立的;一旦改的是内部的可变内容,两者就一起受影响。
a=[1,2,3,4,[5,6]]
b=a.copy()
a.append(111)
b[-1].append(123)
print(a)
print(b)
输出:
[1, 2, 3, 4, [5, 6, 123], 111]
[1, 2, 3, 4, [5, 6, 123]]
第一个append,只改变了a,在a的末尾加了个111.
第二个append,同时改变了a,b。
5.深拷贝
copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象
完全独立了此时,注意下语法
import copy
a=[1,2,3,4,[5,6]]
b=copy.deepcopy(a)
a.append(111)
b[-1].append(123)
print(a)
print(b)
输出:
[1, 2, 3, 4, [5, 6], 111]
[1, 2, 3, 4, [5, 6, 123]]
各自改各自的,互不影响。
其实,大部分时间都是深拷贝的需求,但会陷入浅拷贝的坑,一定要注意。
此bug曾坑过我一次。。。而且在缺失这部分的知识时,此bug极难发现。
在此做个记录。