python的拷贝一般有三个方法:
直接赋值
浅拷贝
深拷贝
直接赋值
顾名思义,把一个变量赋值给另一个变量,上代码:
a=[1,2,3] :
b=a :
id(a) #在内存中的地址 :
2594082675264 :
id(b) #a和b占用同一个内存 :
2594082675264 :
a.append(4) :
a :
[1, 2, 3, 4] :
b :
[1, 2, 3, 4] :
我们发现通过b=a这种形式赋值深拷贝浅拷贝,两个变量的id()函数值是一样的,即两个变量占用同一个内存地址,相当于b只是a的一个别名,当修改a的值时,b也会跟着一起变。
2. 浅拷贝
浅拷贝是使用copy库的copy()方法进行拷贝,且看代码:
In [8]: import copy
In [9]: a=10
In [10]: b=copy.copy(a)
In [11]: id(a)
Out[11]: 140730619471952
In [12]: id(b)
Out[12]: 140730619471952
In [13]: a1='这是一个字符串'
In [14]: b1=copy.copy(a1)
In [15]: id(a1)
Out[15]: 2594085680496
In [16]: id(b1)
Out[16]: 2594085680496
In [17]: a2=(3,6,9)
In [18]: b2=copy.copy(a2)
In [19]: id(a2)
Out[19]: 2594085623040
In [20]: id(b2)
Out[20]: 2594085623040
我们发现当浅拷贝对象是数值、字符串和元组等不可变类型时,copy.copy()函数只拷贝地址空间,不开辟新的地址空间。所以对于这三种不可变类型的变量而言,浅拷贝只是起个别名而已,而且它们是不可变类型,不存在修改后别名变量值变不变的问题。
再看:
a4=[666,888] :
b4=copy.copy(a4) :
In [38]: id(a4)
2594085696064 :
In [39]: id(b4)
2594085766912 :
a4.append(999) :
In [41]: a4
[666, 888, 999] :
In [42]: b4
[666, 888] :
当浅拷贝对象是列表、字典和集合等可变类型时,copy.copy()函数会开辟新的存储空间来存储拷贝对象,当原变量的值改变时,拷贝变量的值不会变。
3.深拷贝
深拷贝是使用copy库的deepcopy()方法进行拷贝,代码如下:
In [21]: a1=[2,3,4]
In [22]: b1=copy.deepcopy(a1)
In [23]: id(a1)
Out[23]: 2594082796928
In [24]: id(b1)
Out[24]: 2594085748416
In [25]: a2={'元宵节':'正月十五','端午节':'五月初五','中秋节':'八月十五'}
In [26]: b2=copy.deepcopy(a2)
In [27]: id(a2)
Out[27]: 2594085793664
In [28]: id(b2)
Out[28]: 2594082725056
In [29]: a3={'北京','上海','广州'}
In [30]: b3=copy.deepcopy(a3)
In [31]: id(a3)
Out[31]: 2594083778112
In [32]: id(b3)
Out[32]: 2594083777440
In [33]: a1.append(666)
In [34]: a1
Out[34]: [2, 3, 4, 666]
In [35]: b1
Out[35]: [2, 3, 4]
很容易看出来,当深拷贝对象是列表、字典和集合等可变类型时,deepcopy()函数会开辟一个新的地址空间来存储拷贝变量。当原变量的值改变时,拷贝变量的值不会改变。
如果深拷贝对象是不可变类型呢?同样是
In [51]: a='OK'
In [52]: b=copy.deepcopy(a)
In [53]: id(a)
Out[53]: 2593981224112
In [54]: id(b)
Out[54]: 2593981224112
In [55]: a="OK!"
In [56]: a
Out[56]: 'OK!'
In [57]: b
Out[57]: 'OK'
In [58]: id(a)
Out[58]: 2594082723952
In [59]: id(b)
Out[59]: 2593981224112
对于字符串等不可变类型来说,深拷贝也不会创建一个新的存储单元。但这里有一个问题,因为字符串是不可变类型,当对变量a重新赋值时,相当于变量a存储的字符串变了,指向的存储单元也变了。
总结一下:
1. 列表、字典和集合是可变类型深拷贝浅拷贝,数值、元组和字符串是不可变类型;
2. 直接赋值只是起一个别名,不开辟新的存储空间;
3. 浅拷贝对不可变类型不开辟新的地址空间,对可变类型开辟新的地址空间;
4. 深拷贝对可变类型的变量开辟新的地址空间,对不可变类型的变量不开辟新的地址空间,但对变量重新赋值时,变量指向的存储空间会发生改变。
深拷贝和浅拷贝的区别是python程序员面试最常见的问题之一,望有兴趣的同学们多多复习,加深理解!