在Python中,一切皆为对象,对象通过「变量名」引用,「变量名」更确切的叫法是「名字」,好比我们每个人都有自己的名字一样,我们通过名字来代指某个人,代码里面通过名字来指代某个对象。
通过x2修改对象时,x3也会跟着变化,因为本质上它们是同一个对象,这就好比一个人大名x2,小名x3,x2长了一岁相对于x3也长了一岁。
变量赋值就是给对象绑定一个名字,赋值多出一个对象。好比出生的时候父母给我们取了一个大名后,再取一个小名并不来多出一个人来,只是多一个名字罢了。
对象赋值
两个对象做比较有两种方式,分别是:is与 == ,is比较的是两个对象是否相同,通过对象的ID值可识别是否为相同对象,==比较的是两个对象的值是否相等。x1 = [1,2,1] x2 = [1,2,1] print(x1 is x2) print(x1 == x2) print(id(x1)) print(id(x2))
False
True
2004573077256
2004573077448
上面我们对x1和x2进行赋值,相对于给两个变量分别取了名字x1和x2,两个名字虽然都是列表[1,2,1],但在内存中是两个独立的不同的对象,占据不同的内存空间,就好比两个名字一样的人,实则为两个不同的人。
x3 = x2 print(x2 is x3)
True上面我们将x2对应的对象绑定了一个新的名字叫x3,这就好比一个人,开始给他取了一个x2的大名,后来又给他取了一个x3的小名,本质上还是同一个人,所以,x2和x3所指的其实是同一个对象。
通过x2修改对象时,x3也会跟着变化,因为本质上它们是同一个对象,这就好比一个人大名x2,小名x3,x2长了一岁相对于x3也长了一岁。
x2.append(2) print(x2) print(x3)
[1, 2, 1, 2] [1, 2, 1, 2]
但是,当我们给x2重新赋值时,相当于x2不再引用之前的对象,而引用新对象,x3依然引用之前的对象。好比一个人的大名x2和小名x3,给x2重新赋值就相当于给另外一个人取大名x2,但是x3还是开始那个人的小名。
x2 = [3,4,3] print(x2) print(x3)
[3, 4, 3] [1, 2, 1, 2]
对象拷贝
有时我们需要复制一个对象,但是又不想对原对象产生副作用,肯定不能通过赋值给一个新变量来解决(因为赋值会对新变量产生影响),所以 Python专门提供了一种拷贝机制,基于原对象快速创建出一个含有相同值的对象。该功能由copy模块提供。import copy
拷贝又分为浅拷贝和深拷贝。
a = [1,2,1] ac = copy.copy(a) #浅拷贝 adc = copy.deepcopy(a) #深拷贝 print(ac) print(adc)拷贝出来的对象只是值相同,实为不同的对象
print(a == ac ==adc) print(a is ac) print(a is adc)
True False False
拷贝出来的对象不在受原来对象的影响
a.append(2) print(a) print(ac) print(adc)
[1, 2, 1, 2] [1, 2, 1] [1, 2, 1]
那么浅拷贝(shallow copy)与深拷贝(deep copy)有什么区别呢?
对于不可变对象,比如整数、字符串、元组、还有由这些不可变对象组成的集合对象,浅拷贝和深拷贝没有区别,都是拷贝一个新对象。两者的区别在于拷贝组合对象,比如列表中还有列表,字典中还有字典或者列表的情况时,浅拷贝只拷贝了外面的壳子,里面的元素并没有拷贝(里面的元素还是引用旧对象),而深拷贝则是把壳子和里面的元素都拷贝了一份新的。
x = [[5,6],[6,7],[7,2] ,[2,5] ,[4,9]] xc = copy.copy(x) #浅拷贝 xdc = copy.deepcopy(x) #深拷贝 print(x[0] is xc[0]) print(x[0] is xdc[0])
True False
我们可以通过下面看到列表中的列表在浅拷贝时会受列表中列表变化而改变
x[0].remove(5) print(x) print(xc) print(xdc)
[[6], [6, 7], [7, 2], [2, 5], [4, 9]] [[6], [6, 7], [7, 2], [2, 5], [4, 9]] [[5, 6], [6, 7], [7, 2], [2, 5], [4, 9]]
浅拷贝只拷贝了x的对象外壳,里面的列表还是引用x里面列表的对象,深拷贝即拷贝了x的对象外壳,而且里面的列表的对象也拷贝了。