1. 程式人生 > >python的深複製和淺複製

python的深複製和淺複製

# -*- coding:UTF-8 -*- 
#此次練習主要是討論物件的淺複製和深複製


import copy


#淺複製一個object有三種方式:1、slice操作;
#                            2、copy模組的copy函式;
#			     			 3、工廠函式:dict()、list()、tuple()


#***********************淺複製*********************************
#淺複製沒有完全的複製一個物件,只是建立一個指向原來物件的reference


#比如:
origList = ['name',['linkin','age']]  #原來列表的元素有兩個:string 和 list 型別
#接下來進行三種方式的淺複製:
frtList = origList[:]
secList = copy.copy(origList)
thrList = list(origList)
#雖然此時三個list的記憶體地址都是不一樣的,但是list中各個元素與origList的
#各個元素的記憶體地址都是一樣的,只是原來列表元素的reference!
#檢視四個列表的元素:
for x in (origList,frtList,secList,thrList):
	print x
print
'''
stdout:
        ['name', ['linkin', 'age']]
        ['name', ['linkin', 'age']]
        ['name', ['linkin', 'age']]
        ['name', ['linkin', 'age']]
'''
#檢視記憶體地址:
for x in (origList,frtList,secList,thrList):
	print id(x),      #不一樣的容器物件地址,其內容本質是一樣的引用
print
print '以上是四個list的記憶體地址'
#輸出結果:
#	28078688 33755424 33537200 33536760(表面:不一樣的容器記憶體地址)


#檢視三個list物件元素的記憶體地址:
for x in (origList,frtList,secList,thrList):
	for elements in x:		
			print id(elements),
print
print '以上是四個list改變前所有元素物件(2個)的記憶體地址'
'''輸出結果:(未對各個物件做任何改動,只是單純的進行淺複製)
      19580064 35853776
      19580064 35853776
      19580064 35853776 
      19580064 35853776 (本質:一樣的元素記憶體地址(表明只是複製
                               的物件只是建立一個新的容器,裡面的
                               複製元素只是指向原來origList列表元素的引用))
'''
#針對淺複製的操作,對某一個列表的元素進行操作時,其他的列表對應的元素也會發生改變
#i.e.
frtList[1][0] = 'changes'
for x in (origList, frtList,secList,thrList):
	print x
print
#結果:
'''
['name', ['changes', 'age']]
['name', ['changes', 'age']]
['name', ['changes', 'age']]
['name', ['changes', 'age']]
	結果的改變只是因為列表改變的元素是mutable物件 list 如果改變的是immutable物件(string\
 	int(tuple稍後再討論)),那麼對其他的列表物件沒有任何影響
'''
#例如:
frtList[0] = 'changeimmutableElems'
for x in (origList, frtList,secList,thrList):
	print x
print 
'''
輸出結果:
['name', ['changes', 'age']]
['changeimmutableElems', ['changes', 'age']]
['name', ['changes', 'age']]
['name', ['changes', 'age']]


'''
#檢視記憶體地址:
print '以下是改變第二list物件frtList後各個列表所有元素的記憶體地址:'
for x in (origList, frtList,secList,thrList):
	for elements in x:		
			print id(elements),
print
'''結果:
   19580064 35853776
   35846816 35853776  被改變的元素(immutable物件)記憶體地址改變    
   19580064 35853776
   19580064 35853776


原因:因為string型別是immutable型別,想要對不可改變型別進行改變?那麼只有重新建立
	  string型別的字串再賦值給frtList[0],那麼此時frtList[0]元素記憶體地址已經改變
	  然而,如果元素師mutable型別如 list型別,其元素的改變是允許的,改變後的list物件
	  的記憶體地址還是不變(因為是mutable型別),所以引用發生改變,其他的淺複製元素引用
	  也發生改變
'''


#************************************深複製****************************


#進行物件的深複製只需要使用deepcopy函式:
deepList = copy.deepcopy(origList)


print '深複製之後(改變前)的列表物件記憶體地址和內容:'
for x in (origList,deepList):
	print id(x),'-->',x
print
print '改變前列表元素的記憶體地址和內容:'
for x in (origList,deepList):
	for item in x:
		print id(item),'-->',item
print
'''stdout:
		深複製之後(改變前)的列表物件記憶體地址和內容:
		28602976 --> ['name', ['changes', 'age']]
		34150600 --> ['name', ['changes', 'age']]
		改變前列表元素的記憶體地址和內容:
		23184544 --> name
		34149240 --> ['changes', 'age']
		23184544 --> name
		34151240 --> ['changes', 'age']


'''
#分別對string、list型別的元素進行改變:
print '深複製之後(改變後)的列表物件元素記憶體地址和內容:'
deepList[0] = 'strchanges'
deepList[1][0] = 'listchanges'
for x in (origList,deepList):
	print id(x),'-->',x
print
print '改變後列表元素的記憶體地址和內容:'
for x in (origList,deepList):
	for item in x:
		print id(item),'-->',item
print
'''
stdout:
	
		深複製之後(改變後)的列表物件元素記憶體地址和內容:
		28602976 --> ['name', ['changes', 'age']]             #兩個列表互不影響!!
		34150600 --> ['strchanges', ['listchanges', 'age']]
		改變後列表元素的記憶體地址和內容:
		23184544 --> name
		34149240 --> ['changes', 'age']
		34175136 --> strchanges
		34151240 --> ['listchanges', 'age']
'''