一、疑惑
今天在看《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 =" 不行麼?這兩者間有什麼區別呢?
二、線索
疑惑主要集中在對切片進行賦值上。抱著「實踐是檢驗真理的唯一標準」,竹風做了個小實驗:
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']。
三、真相
那麼真相是什麼呢,讓我們繼續實踐一下:
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[:] =" 寫法。簡單地說,使用切片賦值可以修改原物件的類容,而不是建立乙個新物件。謝謝大家~~
Python切片和切片賦值
a 1,2,3 b a 切片 a 1 切片賦值切片 在右側,切片賦值 在左側 切片是淺拷貝,不影響原序列 切片賦值是針對原序列進行操作,改變切片區域的序列。切片賦值,給序列的切片部分新的賦值必須是可迭代型別 a 1,2,3 a 1 2 3 typeerror can only assign an i...
C 札記 賦值相容
賦值相容的規則時在需要使用基類物件的任何地方都可以使用公有派生類物件來替代。公有繼承派生類可獲得基類中除建構函式,析構函式外的所有成員,能用基類解決的問題,派生類也能解決。更直白點說,如果乙個類是從乙個基類公有繼承過來,那麼這個派生類就可以替代基類,反過來基類不能替代派生類。常用賦值相容情況 1.派...
python 切片 Python 列表切片
想必很多人都使用過列表的切片,通過切片可以從列表中獲取乙個或多個元素,但你真的了解切片?一 一般玩法 name a b c d e f g h name 0 2 獲取 0 2 中間的元素,不包括索引為 2 的元素 a b name 2 從 0 開始切,可省略 0 a b name 1 同樣地,切到最...