Python的賦值、深拷貝與淺拷貝的區(qū)別詳解
在python中,給一個對象賦值,實際上就是對象對內(nèi)存空間存儲的值的引用。當(dāng)我們把對象賦值給另一個變量的時候,這個變量并沒有拷貝這個對象,而只是拷貝了這個對象的引用而已。
一般情況下我們會通過三種方法來實現(xiàn)拷貝對象的引用。
Python直接賦值
直接賦值,默認(rèn)淺拷貝傳遞對象的引用而已,原始列表改變,被賦值的變量也會做相同的改變。其實就是對‘對象'的引用
示例:
>>> list_demo = [2, 4, 6] >>> a = list_demo >>> print(a) [2, 4, 6] >>> id(list_demo) 65006808 >>> id(a) 65006808 >>> list_demo.append(8) >>> print(list_demo) [2, 4, 6, 8] >>> print(a) [2, 4, 6, 8] >>> id(list_demo) 65006808 >>> id(a) 65006808 >>>
通過 id() 函數(shù)我們可以得出,變量 list_demo 與 a 指向的都是同一個內(nèi)存空間地址,當(dāng)被賦值的 list_demo改變,被賦值的 a 同樣會做相同的改變。這種現(xiàn)象普遍存在于 Python 之中,這種賦值的方式實現(xiàn)了 “假裝” 拷貝,真實的情況還是兩個變量和同一個對象之間的引用關(guān)系。
Python淺拷貝
import copy 模塊的 copy.copy() 方法,該方法只拷貝父對象,沒有拷貝子對象。且淺拷貝是創(chuàng)建一塊新的內(nèi)存空間,但是內(nèi)存空間內(nèi)的元素的地址均是父對象元素的地址的拷貝。所以當(dāng)父對象內(nèi)部的子對象發(fā)生改變時,拷貝對象的內(nèi)部的子對象也會跟著改變。
示例:
>>> list_demo1 = [2, 4, 6, [8, 10]] >>> a = list_demo1 >>> print(list_demo1) [2, 4, 6, [8, 10]] >>> print(a) [2, 4, 6, [8, 10]] >>> >>> >>> import copy >>> b = copy.copy(list_demo1) >>> id(list_demo1) 65103472 >>> id(b) 6011200 >>> list_demo1.append(12) >>> print(list_demo1) [2, 4, 6, [8, 10], 12] >>> list_demo1[3] [8, 10] >>> >>> >>> >>> list_demo1[3].append('hello') >>> print(list_demo1) [2, 4, 6, [8, 10, 'hello'], 12] >>> print(b) [2, 4, 6, [8, 10, 'hello']] >>> list_demo1[3] [8, 10, 'hello'] >>> b[3] [8, 10, 'hello'] >>> >>> >>> >>> id(list_demo1) 65103472 >>> id(b) 6011200 >>> id(list_demo1[3]) 64679128 >>> id(b[3]) 64679128 >>>
從上述代碼可以看出,在執(zhí)行淺拷貝的時候,淺拷貝實際上只拷貝引用,不拷貝內(nèi)容。同時,淺拷貝會針對父對象的子對象進(jìn)行判斷,當(dāng)父對象的子對象發(fā)生改變時,拷貝對象內(nèi)的子對象同時也跟著改變。
Python深拷貝
import copy 模塊的 copy.deepcopy() 方法,深拷貝與淺拷貝相反,就是徹徹底底的拷貝,完全的拷貝了父對象及子對象,同時指向一個新的內(nèi)存空間地址。此時,雖然源對象與拷貝對象的內(nèi)容是一樣的,但是不管針對誰進(jìn)行改動,另一個是絲毫不會受到影響的。
>>> list_demo2 = [2,3,4]
>>> c= copy.deepcopy(list_demo2)
>>> print(list_demo2)
[2, 3, 4]
>>> print(c)
[2, 3, 4]
>>> id(list_demo2)
6011440
>>> id(c)
6012440
>>> list_demo2.append(['a','b'])
>>> c.append([5,6])
>>> print(list_demo2)
[2, 3, 4, ['a', 'b']]
>>> print(c)
[2, 3, 4, [5, 6]]
>>> list_demo2[3].append('c')
>>> c[3].append(7)
>>> print(list_demo2)
[2, 3, 4, ['a', 'b', 'c']]
>>> print(c)
[2, 3, 4, [5, 6, 7]]
>>>
從上述代碼示例可以看出 list_demo2 與 c 相互獨立,無論 list_demo2 與 c本身進(jìn)行了修改,或者各自的子對象進(jìn)行了修改 都沒有互相影響。
總結(jié)
Python賦值
賦值的本質(zhì)就是將一個對象的內(nèi)存空間地址賦值給一個變量,讓變量指向該內(nèi)存空間地址。
Python淺拷貝
淺拷貝是拷貝了源對象的引用,并創(chuàng)建了一個新的內(nèi)存空間地址。但是引用的對象的子對象的地址仍然是源對象的,所以當(dāng)源對象的子對象發(fā)生改變時,拷貝對象內(nèi)的子對象同時也跟著改變。
Python深拷貝
深拷貝就是徹底的拷貝,完全的拷貝了父對象及子對象,同時指向一個新的內(nèi)存空間地址。源對象與拷貝對象之間的修改互不影響。
更多關(guān)于Python的賦值、深拷貝與淺拷貝的區(qū)別文章請查看下面的相關(guān)鏈接
相關(guān)文章
對Python 除法負(fù)數(shù)取商的取整方式詳解
今天小編就為大家分享一篇對Python 除法負(fù)數(shù)取商的取整方式詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-12-12Python使用matplotlib 模塊scatter方法畫散點圖示例
這篇文章主要介紹了Python使用matplotlib 模塊scatter方法畫散點圖,結(jié)合實例形式分析了Python數(shù)值運算與matplotlib模塊圖形繪制相關(guān)操作技巧,需要的朋友可以參考下2019-09-09Jupyter Notebook運行Python代碼實現(xiàn)傳參方式
這篇文章主要介紹了Jupyter Notebook運行Python代碼實現(xiàn)傳參方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07Python 中l(wèi)ist ,set,dict的大規(guī)模查找效率對比詳解
這篇文章主要介紹了Python 中l(wèi)ist ,set,dict的大規(guī)模查找效率對比詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10Python使用textract實現(xiàn)從各種文件中提取文本信息
textract是一個強大的Python庫,可以用于從各種文件格式中提取文本,本文將介紹textract的使用場景,以及一些常用的Python代碼案例,希望對大家有所幫助2024-01-01解決pycharm 工具欄Tool中找不到Run manager.py Task的問題
今天小編就為大家分享一篇解決pycharm 工具欄Tool中找不到Run manager.py Task的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07舉例簡單講解Python中的數(shù)據(jù)存儲模塊shelve的用法
這篇文章主要介紹了舉例簡單講解Python中的數(shù)據(jù)存儲模塊shelve的用法,shelveshelve模塊與pickle模塊的功能相近,比pickle用起來更為簡單,需要的朋友可以參考下2016-03-03