第八章 對象引用、可變性
本章討論的是對象與對象名稱之間的區別。名稱不是對象,而是單獨的東西。
變數不是盒子
Python中的變數很像java中的引用變數,也就是說,變數里存著的並不是變數本身,而是對於內容的引用(C中的指針)。這樣說起來可能有點繞口,我們來通過一個小列子感受一下:
a = [1,2,3]nb = a nb.append(4)nprint(a)nnnOUT:n[1, 2, 3, 4]nn
變數a、b同時引用了同一個列表[1,2,3]
b並不是那個列表的拷貝。為了更好地理解Python中的賦值語句,我們應該始終讀式子的右邊。對象再右邊創建或獲取,再次之後,才會綁定到左邊的變數上。這就像為對象貼上了「標註」,而不是用盒子把對象裝起來。
標識、相等性、別名
ehco = {name:ehco,age:21}nxiaozhou = ehconnprint(xiaozhou == ehco )nprint(xiaozhou is ehco)nprint(id(xiaozhou),id(ehco))nnfake_ehco = {name:ehco,age:21}nprint(fake_ehco==ehco)nprint(fake_ehco is ehco)nprint(id(fake_ehco),id(ehco))nnnnOUT:nTruenTruen4477069280 4477069280nnTruenFalsen4561643560 4561643488nn
在這裡,xiaozhou即為ehco的別名,我們通過id函數確認了:
xiaozhou和ehco實際上引用的是同一個字典對象:{name:ehco,age:21}fake_ehco的值雖然和ehco一樣,
但實際上他們兩個是兩個獨立的對象這是因為,每個變數都有標識,類型和值,對象一旦創建,他的標識絕對不會變,(標識積內存地址) 可以通過id函數來得到標識,而is函數則是比較對象之間的id是否相同。
比較時是用is還是== ?
這個問題其實很簡單。
當我們只關心變數的值的時候,我們用==
其他的時候,我們應該用is默認為淺複製
複製列表(或者其他內置的可變集合)最簡單的方式是使用內置類型的構造方法。
而然這種複製是淺複製,如果元素都是不可變的,那麼沒有問題,但如果元素包含了可變類型,那麼結果可能就不是我們想要的了。
l1 = [1,2,3,[4,5]]nnl2 = list(l1) # 通過構造方法進行複製 nl2 = l1[:] #也可以這樣想寫nnnl2.append(9)nprint(l1: {} nl2: {}.format(l1,l2))nnl2[3].append(8)nprint(l1: {} nl2: {}.format(l1,l2))nnnnOUT:nnl1: [1, 2, 3, [4, 5]]nl2: [1, 2, 3, [4, 5], 9]nnl1: [1, 2, 3, [4, 5, 8]]nl2: [1, 2, 3, [4, 5, 8], 9]nn
可以看到,我們通過list的構造方法,十分便捷的複製了l1
通過第一個輸出,我們能看到l2和l2是兩個獨立的對象。可通過第二個輸出,
我們明明沒有對l1進行操作,
可存在l1里的列表的值也更新了這就是淺複製帶來的弊端了。l1[3] 里寸的是另外一個列表的引用,這是一個可變的對象,所以在進行複製操作時,
l1[2] 和 l1[3]內引用的對象是同一個。那麼如何進行深度複製呢?
copy 模塊中的copy() 和 deepcopy() 函數可以對任意對象進行淺複製和深度複製。本章小結
本章著重說了:每個Python對象都有其標識,類型和值,但只有對象的值會發生改變。
每個對象唯一的身份id可以用其內存地址表示,用id函數就能獲取
關於可變類型和不可變類型我們通過幾個例子,有了更加深入的了解
在複製變數的時候,記住默認是淺複製。
這就引申到了下面幾點:
- 函數的參數 (不要使用可變類型作為參數的默認值)
- Python的垃圾回收機制 (這裡我也描述不好,有興趣可以查閱相關書籍)
每天的學習記錄都會 同步更新到:
微信公眾號: findyourownway知乎專欄:https://zhuanlan.zhihu.com/zen-of-pythonBlog : www.ehcoblog.mlGithub: https://github.com/Ehco1996/推薦閱讀:
※python教程看完了,還是不會編程?
※二廠開工——Fake Cuneiform
※Python3《機器學習實戰》學習筆記(九):支持向量機實戰篇之再撕非線性SVM
※【翻譯搬運】SciPy-Python科學演算法庫
※pycham如何整合pyqt5並安裝qtdesigner?
TAG:Python |