Python札記 -- 切片賦值

1、疑惑
    今天在看《Python Cookbook》第四章Python技巧的4.7小節時,發現一段初看起來讓人疑惑的代碼。該小節的任務是將一個包含列表(行)的列表,轉換成一個新的列表。新的列表包含了一樣的行,可是其中一些列被刪除或者從新排序了。讓人疑惑的代碼以下:測試

1 listOfRows = [[1,2,3,4], [5,6,7,8], [9,10,11,12]]
2 listOfRows[:] = [[row[0], row[3], row[2]] for row in listOfRows]

竹風不由疑惑了,這第二行的代碼爲啥會用 "listOfRows[:] =" 這種寫法?直接寫成 "listOfRows =" 不行麼?這二者間有什麼區別呢?spa

2、線索
    疑惑主要集中在對切片進行賦值上。抱着「實踐是檢驗真理的惟一標準」,竹風作了個小實驗:code

 1 >>> test_li = ['a','b','c','d','e','f']    #進行測試的list
 2 >>> test_li[1:4]    #簡單的切片操做
 3 ['b', 'c', 'd']
 4 >>> id(test_li)    #觀察一下測試list的id
 5 139718916544776
 6 >>> test_li[1:4] = [1,2]    #對切片進行賦值,並且是不對等的賦值
 7 >>> test_li    #觀察賦值後的list
 8 ['a', 1, 2, 'e', 'f']
 9 >>> id(test_li)    #id沒有變化,說明是在原對象上進行修改
10 139718916544776
11 >>>

配合註釋來看的話,對切片賦值貌似是在原對象上進行修改。並且值得注意的是,切片賦值還支持元素個數不相等的操做,好比實驗中用[1,2]替換了['b','c','d']對象

3、真相
    那麼真相是什麼呢,讓咱們繼續實踐一下:blog

 1 >>> listOfRows = [[1,2,3,4], [5,6,7,8], [9,10,11,12]]
 2 >>>
 3 >>> li = listOfRows
 4 >>> id(listOfRows)
 5 139718916543336
 6 >>> id(li)    #二者的id相同,說明引用了同一個對象
 7 139718916543336
 8 >>> listOfRows = [[row[0], row[3], row[2]] for row in listOfRows]
 9 >>> listOfRows    #使用列表推導產生的結果符合預期
10 [[1, 4, 3], [5, 8, 7], [9, 12, 11]]
11 >>> li    #li沒有改變
12 [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
13 >>> id(listOfRows)
14 139718916544416
15 >>> id(li)    #二者id不一樣,說明listOfRows綁定了一個新的對象
16 139718916543336
17 >>>

直接使用 "listOfRows =" 的話,產生了一個新的對象,讓咱們繼續看看 "listOfRows[:] =" 的效果:排序

 1 >>> listOfRows = [[1,2,3,4], [5,6,7,8], [9,10,11,12]]
 2 >>> 
 3 >>> li = listOfRows
 4 >>> id(listOfRows)
 5 140034137774560
 6 >>> id(li)    #二者id一致,引用了同一個對象
 7 140034137774560
 8 >>> listOfRows[:] = [[row[0], row[3], row[2]] for row in listOfRows]
 9 >>> listOfRows    #使用切片賦值,達到預期效果
10 [[1, 4, 3], [5, 8, 7], [9, 12, 11]]
11 >>> li    #li也發生了變化,由於二者綁定的是同一個對象
12 [[1, 4, 3], [5, 8, 7], [9, 12, 11]]
13 >>> id(listOfRows)
14 140034137774560
15 >>> id(li)    #二者的id都沒有變化,說明切片賦值實在原對象上修改
16 140034137774560
17 >>>

    最後的結束語了:列表推導會產生一個新的列表,而不是修改現有的列表。若是須要一個新的對象,那麼可使用 "listOfRows ="  寫法。當須要修改一個現有的列表時,最好的辦法是將現有列表的內容賦值爲一個列表推導,也就是使用"listOfRows[:] =" 寫法。簡單地說,使用切片賦值能夠修改原對象的類容,而不是建立一個新對象。謝謝你們~~class

相關文章
相關標籤/搜索