1. 程式人生 > >python資料結構之深淺拷貝

python資料結構之深淺拷貝

Python中深淺拷貝詳解

變數-引用-物件(可變物件,不可變物件)-切片-拷貝(淺拷貝,深拷貝)

變數:在Python中一切都是物件,比如:3,3.14,“Hello world”,【1,2,3,4】,{‘a’:1}….

輸出:

甚至連Type其本身也是物件,type物件

Python中的變數指物件的引用,Python是動態型別,程式執行時會根據物件的型別來確認變數到底是什麼型別

比如:a=3

其中變數a是物件3的一個引用。在程式內部,變數事實上是到物件記憶體空間的一個指標

https://img-blog.csdn.net/20141210215031875

變數:指一個元素,擁有指向物件的連線空間

物件:被分配的一個記憶體,儲存其所代表的值

引用:自動形成的從變數到物件的指標

共享引用:比如:

輸出:

可以看出變數a和b指向了同一個物件的記憶體空間

可變物件:在Python中指可以修改的物件,例如:列表,字典

不可變物件:在Python中指不能改變的物件,例如:字串、元組、數字

L1=[3,4,5,6,7,8,9]#L1變數指向一個可變物件:列表
L2=L1#將L1的值賦給L2後,兩者共同引用同一個物件
L1[0]=300#將L1列表中的第一個元素改變
print(L1,L2)



輸出:
#[300, 4, 5, 6, 7, 8, 9] [300, 4, 5, 6, 7, 8, 9]

可以看出改變L1之後,L2的值跟著改變了,如果不想讓L2跟著改變,可以採用切片或者拷貝的方法

L1=[2,3,4,5,6,7]
L2=L1[:]#切片操作
print(id(L1),id(L2))#切片後物件就不一樣了
L1[0]=200
print(L1,L2)#L1改變,L2不改變



輸出:
12966968 12965408
[200, 3, 4, 5, 6, 7] [2, 3, 4, 5, 6, 7]

切片:與使用索引來訪問單個元素類似,可以使用切片操作來訪問一定範圍內的元素。切片通過冒號隔開兩個索引來實現

拷貝:切片操作可以應用在所有的序列中,例如:列表、元組、字串,但是不能用在字典當中,對字典只能使用D.copy()方法或D.deepcopy()方法,深淺拷貝可以用在序列當中,也可以應用在字典中。

import copy

   X = copy.copy(Y)      #淺拷貝:只拷貝頂級的物件,或者說:父級物件

    X = copy.deepcopy(Y)  #深拷貝:拷貝所有物件,頂級物件及其巢狀物件。或者說:父級物件及其子物件

程式碼實現:

如果字典中只含有頂級物件

import copy
D={'age':20,'name':'zhangsan'}#原始字典
C1=copy.copy(D)#淺拷貝
C2=copy.deepcopy(D)#深拷貝
print(id(D),id(C1),id(C2))#三個不同物件
D['name']='lisi'#改變源字典
print(D,C1,C2)


輸出:
28681296 28681728 59780144
{'age': 20, 'name': 'lisi'} {'age': 20, 'name': 'zhangsan'} {'age': 20, 'name': 'zhangsan'}
#可以看出只改變了原始字典中的物件值

如果字典中含有巢狀物件

import copy
D={'name':{'first':'zhang','last':'san'},'jobs':['IT','HR']}#原始字典含有巢狀物件
C1=copy.copy(D)#淺拷貝
C2=copy.deepcopy(D)#深拷貝
D['jobs'][0]='data'#改變原始字典中的jobs子物件‘it'變為’data'
print(D,C1,C2)



輸出:
{'name': {'first': 'zhang', 'last': 'san'}, 'jobs': ['data', 'HR']} {'name': {'first': 'zhang', 'last': 'san'}, 'jobs': ['data', 'HR']} {'name': {'first': 'zhang', 'last': 'san'}, 'jobs': ['IT', 'HR']}
#可以看出淺拷貝受影響,深拷貝不受影響

結論:

深淺拷貝都是對源物件的複製,佔用的是不同的記憶體空間

如果源物件只含一級目錄,深淺拷貝不受影響

如果含多級目錄,淺拷貝受影響,深拷貝不受影響

切片屬於淺拷貝

=                        :地址相同;原值改變,值隨之改變

copy.copy()        :可變型別(list、dict)地址不同;原值改變,值隨之改變

                              不變型別(tuple)地址相同;值不可變

copy.deepcopy():地址不同;原值改變,值不隨之改變

深淺拷貝的作用:
1,減少記憶體的使用 
2,以後在做資料的清洗、修改或者入庫的時候,對原資料進行復制一份,以防資料修改之後,找不到原資料。

對於不可變物件的深淺拷貝:
不可變物件型別,沒有被拷貝的說法,即便是用深拷貝,檢視id的話也是一樣的,如果對其重新賦值,也只是新建立一個物件,替換掉舊的而已。

一句話就是,不可變型別,不管是深拷貝還是淺拷貝,地址值和拷貝後的值都是一樣的。
 

參考文獻:https://blog.csdn.net/u012377333/article/details/41956727