在Python中,字符串、列表、字典是能够很容易进行相互转换的,这无疑增加了Python数据结构的灵活性。但是作为几大数据结构中的成员,它们又存在一些非常值得我们注意的差别,很典型的情况就是进行引用与复制时,注意不同对象结构下带来结果的不同。
在C/C++中,复制分为深复制和浅复制。它们的区别就在于复制对象的差别,浅复制只是实现对指针的拷贝,最后两个指针指向内存空间的同一个地址;深复制则不仅仅实现对指针的拷贝,还实现了对指针所指内容的拷贝,就是说,最后两个指针指向了内容空间的不同地址。由此看来,浅复制是不太可靠的,因为在实施浅复制后,如果一个指针改变了指向内容,那么其他指针指向的内容也会随之改变,他们本来就指向的同一个内容。
同样的,Python中也存在深复制与浅复制。
对于字符串,由于字符串是不可变对象,调用对象自身的任意方法,也不会改变该对象自身的内容。所以用=可以实现复制,这里的复制本质上是对原来对象的引用。
String = "abcd"
String1 = String
String2 = String.strip('a')
print String, String1, String2
但是对于列表和字典,他们是可变对象,调用对象自身的任意方法,会改变该对象自身的内容。所以用=只能实现引用。
用自身list[:]或dict.copy()方法实现浅复制,但是注意的是,虽然这两种办法能实现对象的复制,但是一旦对象包含的元素是可变的嵌套结构,如列表中嵌套列表,就会导致对这些元素的操作是引用而不是复制。也就是说,当我们改变原来对象某一元素里的数据时,其实经过这两种办法复制过来的对象也是随之改变的。
解决这种办法,需要实现真正的深复制,也就是说对象及其其中的元素都是彻彻底底的开辟新的内存空间进行复制。可以通过copy.deepcopy(list)或copy.deepcopy(dict)方法实现。
下面贴一段代码,加深对list和dict深复制和浅复制的理解:
#coding: utf-8
import copy
## 列表list复制
print "*"*100
List = [0, [1, 2], 3]
List1 = List # 引用
List2 = List[:] # 浅复制,对象复制;但其中元素是引用
List3 = copy.copy(List) # 浅复制,对象复制;但其中元素是引用
List4 = copy.deepcopy(List) # 深复制,对象及其中元素都是复制
print "*"*50
print List, List1
print List2, List3
print List4
print '*'*50
List[0] = 100
print List, List1
print List2, List3
print List4
print '*'*50
List[1][1] = 100
print List, List1
print List2, List3
print List4
## 字典dict复制
print "*"*100
Dict = {'a':0, 'b':[1, 2], 'c':3, 'd':4}
Dict1 = Dict # 引用
Dict2 = Dict.copy() # 浅复制,对象复制;但其中元素是引用
Dict3 = copy.copy(Dict) # 浅复制,对象复制;但其中元素是引用
Dict4 = copy.deepcopy(Dict) # 深复制,对象及其中元素都是复制
print "*"*50
print Dict, Dict1
print Dict2, Dict3
print Dict4
print "*"*50
Dict['a'] = 100
print Dict, Dict1
print Dict2, Dict3
print Dict4
print "*"*50