問題解析:Python中的變數複製備份,為什麼沒有達到效果?
背景
在運用Python進行開發程式碼過程中,會遇到變數複製備份的場景,但並沒有得到預期的結果,例如下面的例子: 加我VX:atstudy-js 回覆“測試”,進入 自動化測試學習交流群~~
lista = ['a', 'b', [1, 2, 3]]
listb = lista.copy()
lista[2].append(4)
print(lista) # ['a', 'b', [1, 2, 3, 4]]
print(listb) # ['a', 'b', [1, 2, 3, 4]]
程式碼本意是將lista複製給listb做個備份,再修改liasta,但是修改後發現listb也一併被修改了,沒有達到備份的效果,這個是什麼原因呢?
儲存方式
首先了解一下Python的變數在記憶體中的儲存方式。在基本資料型別中(包括set、list(tuple, str)、dict)都是採用引用的方式。
也就是說,每個變數都儲存的是這個變數的地址,而不是值本身,就算更復雜的巢狀結構,也是儲存是每個元素的地址而已,用一幅圖來表示。
如上圖所示,使用者看到的是 lista的4個元素值,但是記憶體中儲存的卻是4個元素地址。
當元素是列表時,第一層儲存的是列表的地址,第二層儲存的是列表元素的地址,第三層才是列表的值。當元素是字典的時候,與列表類似。
列表的增刪改
在明白了變數儲存方式後,繼續看下記憶體下的增刪改是怎麼變化的。
列表修改已有值
新增一個記憶體塊,再將引用的地址修改為新記憶體塊的地址。
列表新增一個值
新增一個記憶體塊,新增一個地址引用。
列表整體重新賦值
刪除變數地址和引用的值,新增地址和引用值的記憶體塊。
copy與deepcopy的區別
基於以上的理解,再來看兩種copy的區別就會更容易理解了,首先記住一個原則:
copy:不管多麼複雜的資料結構,淺複製都只會copy一層。
deepcopy:將整個變數記憶體全部複製一遍,新變數與原變數沒有任何關係。
舉個例子來驗證一下上面的結論:有如下的一段程式碼,最終的4個列表值是多少?
注意:引用deepcopy需要匯入copy庫。
import copy
a = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5)
a[1] = 20
a[4].append('c')
del a[0]
print(a)
print(b)
print(c)
print(d)
列表b
表示b也引用的a的地址,兩者引用的記憶體地址是一樣的。因此b和a的關係是緊密相連的,一模一樣。可以透過 id(a) 和id(b)比較,兩者是一樣的。
列表c
由於c是淺複製的a列表,因此只copy了第一層,也就是地址層。
所以,當a.append(5)時,新增了一個記憶體塊,但是c只有前5個記憶體塊,因此c沒有變化。
繼續a修改了a[1],然而這個值是屬於第一層,已經copy給了c,因此c也沒有變化。
繼續a修改了子列表,這個時候a複製給c的只是列表的地址,且a中的子列表地址和c中的子列表地址是指向同一個地方的,因此修改了a中子列表,c中的子列表也會相應的改變。
最後刪除a[0],與修改a[1]一致,與c無關。可以用圖再說明一下。
列表d
由於d是深複製的a列表,因此d是將a的地址和值一併複製過來,與a沒有半點關係,也就是說d和a是兩個完全獨立的記憶體塊,沒有任何交集。因此,後面a的任意修改都與d無關,用圖表示如下。
因此,程式執行出來後的結果就是:
a:[20,3,4,['a','b','c'],5]
b:[20,3,4,['a','b','c'],5]
c:[1,2,3,4,['a','b','c']]
d:[1,2,3,4,['a','b']]
總結
綜上,我們在使用copy的時候,一定要記住:copy只是複製了第一層,而deepcopy才是複製的全部資料。
因此就不難發現,文章背景中的程式碼使用備份功能時,備份列表需要使用deepcopy,而不是簡單的copy。
最後:
可以到我的個人V:atstudy-js,可以免費領取一份10G軟體測試工程師面試寶典文件資料。以及相對應的影片學習教程免費分享!其中包括了有基礎知識、Linux必備、Mysql資料庫、抓包工具、介面測試工具、測試進階-Python程式設計、Web自動化測試、APP自動化測試、介面自動化測試、測試高階持續整合、測試架構開發測試框架、效能測試等。
這些測試資料,對於做【軟體測試】的朋友來說應該是最全面最完整的備戰倉庫,這個倉庫也陪伴我走過了最艱難的路程,希望也能幫助到你!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31407649/viewspace-2922620/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- java中a=a++值為什麼沒有改變?棧運算解析Java
- [譯] React 中的 Immutability:可變物件並沒有什麼問題React物件
- [python]為什麼父類的值沒有改變Python
- 為什麼Python中沒有Switch/Case語句?Python
- 你有沒有想過: 為什麼Java中String是不可變的?Java
- 沒有備份undo segment出現問題的處理
- 解決印象筆記中複製idea等沒有縮排的問題筆記Idea
- 沒有學不會的C++:為什麼不要使用全域性變數C++變數
- 複製SqlServer備份到其他計算機,實現異地備份SQLServer計算機
- Windows 多次製作母盤,備份檔案變大的問題Windows
- 為什麼CDN對移動客戶端加速“沒有”效果客戶端
- 什麼是環境變數?python設定環境變數有什麼用?變數Python
- pg流複製備份
- 【漫畫】為什麼說O(n)複雜度的基數排序沒有快速排序快?複雜度排序
- 為什麼Hook沒有ErrorBoundary?HookErrorORB
- 為什麼Google沒有客服?Go
- python有pypi.org,為什麼golang沒有gopi.orgPythonGolang
- 為什麼 Go 有兩種宣告變數的方式,有什麼區別,哪種好?Go變數
- JS中的陣列複製問題JS陣列
- OB有問必答 | 引數和變數的區別是什麼?變數
- 資料備份與複製
- python變數命名為什麼數字不能開頭?Python變數
- Twitter為什麼沒有當機?
- 為什麼?為什麼?Java處理排序後的陣列比沒有排序的快?想過沒有?Java排序陣列
- 【譯】為什麼Rust中的BTreeMap沒有with_capacity()方法?Rust
- 資料庫連線池的問題,連線池物件為靜態變數有問題麼資料庫物件變數
- 為什麼資料備份那麼重要?
- 在python中什麼是私有變數域Python變數
- 蘋果的設計為什麼難以複製蘋果
- 找出沒有繫結變數的引發硬解析的SQL變數SQL
- 為什麼末世題材的遊戲裡,從來沒有自行車?遊戲
- Python 自動備份SVN版本庫並複製到遠端主機指令碼Python指令碼
- 分析競價推廣為什麼有訪問沒有諮詢KMK
- 為什麼沒有基礎學不好python程式設計?Python程式設計
- Python 中變數賦值傳遞時的引用和複製介紹Python變數賦值
- 香橙派: 複製系統到新sd卡(系統備份)SD卡
- python 複數是什麼意思Python
- 為什麼安裝jdonNews時mysql有問題MySql