Python list
在介紹 Python tuple 時,我使用了類比的方法,將其比做一個袋子,您可以在袋子中存放不同的東西。Python list 與此非常類似,因此,它的功能與袋子的功能也非常類似。但有一點是不同的,即您可以使用方括號創(chuàng)建 list,如清單 1 所示。
清單 1. 在 Python 中創(chuàng)建一個 list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
>>> l = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] >>> l [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] >>> type (l) < type 'list' > >>> el = [] # Create an empty list >>> len (el) 0 >>> sl = [ 1 ] # Create a single item list >>> len (sl) 1 >>> sl = [ 1 ,] # Create a single item list , as with a tuple >>> len (sl) 1 |
本例展示如何創(chuàng)建包含從 0 到 9(包括 0 和 9)的簡單 list,以及如何創(chuàng)建一個空列表和一個包含單個條目的列表。如果您還記得的話,創(chuàng)建單個條目的 tuple 還需要在單個條目后面跟一個逗號。這是區(qū)分單個條目 tuple 與方法調(diào)用的必要條件,這一點將在以后的文章中詳細討論。而對于 list,則是不必要的,盡管也允許使用單個逗號。
與往常一樣,要獲取有關 Python 主題的更多信息,您可以使用內(nèi)置的幫助解釋器,例如,清單 2 展示了如何開始 list 類的幫助描述。
清單 2. 獲取有關 list 的幫助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
>>> help ( list ) Help on class list in module __builtin__: class list ( object ) | list () - > new list | list (sequence) - > new list initialized from sequence's items | | Methods defined here: | | __add__(...) | x.__add__(y) < = = > x + y | | __contains__(...) | x.__contains__(y) < = = > y in x | ... |
如果仔細觀察清單 2 中對 list 類的描述,您會看到其中提供了兩個不同的構造函數(shù):一個沒有參數(shù),另一個接受一個序列類作為參數(shù)。因此,使用構造函數(shù)及方括號簡化符號,可以創(chuàng)建 list。這就提供了很大的靈活性,原因是您可以方便地將現(xiàn)有的序列,如 tuple 或 string 轉(zhuǎn)換為 list,如清單 3 所示。不過,請注意,傳遞的參數(shù)必須是序列 —— 并且不只是對象序列 —— 否則將會出現(xiàn)錯誤。對于任何序列類型,您都可以使用 len 方法容易地查找序列中條目的數(shù)量。
清單 3. 直接創(chuàng)建 list 對象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
>>> l = list () >>> type (l) < type 'list' > >>> len (l) 0 >>> l [] >>> l = list (( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 )) # Create a list from a tuple >>> l [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] >>> len (l) 10 >>> l = list ([ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]) # Create a list from a list >>> l [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] >>> len (l) 10 >>> l = list ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) # Error: Must pass in a sequence Traceback (most recent call last): File "<stdin>" , line 1 , in ? TypeError: list () takes at most 1 argument ( 10 given) >>> l = list ( "0123456789" ) # Create a list from a string >>> l [ '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ] >>> type (l) < type 'list' > >>> len (l) 10 |
正如您看到的,創(chuàng)建 list 是很容易的,如果還沒有嘗試過,現(xiàn)在可以試一試。您不僅能夠?qū)⑿蛄兄苯觽鬟f給構造函數(shù),還可以將擁有元組或字符串的變量傳遞給 list 構造函數(shù)。
很明顯,序列較為有用的主要原因是它可以非常方便地訪問序列中的條目。如果還記得對 tuple 的討論,便知道可以在序列中一次訪問一個條目或者通過將條目切片來訪問條目。Python list 也可以使用相同的技術,如清單 4 所示。
清單 4. 從 list 訪問條目
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
>>> l = list ([ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]) >>> l[ 0 ] # Get the first item in the list 0 >>> type (l[ 0 ]) < type 'int' > >>> l[ 5 ] # Get the sixth item in the list 5 >>> l[ 1 : 5 ] # Get the second through fifth items [ 1 , 2 , 3 , 4 ] >>> type (l[ 1 : 5 ]) < type 'list' > >>> l[ 0 :: 2 ] # Get every second item [ 0 , 2 , 4 , 6 , 8 ] >>> l[ 0 ], l[ 1 ], l[ 2 ] ( 0 , 1 , 2 ) |
在以前的文章中已經(jīng)了解到,切片 是一個非常有用的概念,其一般形式為 l[start:end:step],其中 start 和 end 分別是開始和結束索引,step 是在切片時要跨過的條目數(shù)量。此外,還可以對結束索引使用負值,即從序列的結尾往回計數(shù)。另一個有用的功能是以一種很合適的方式處理錯誤(如超過序列的長度)。如前一個例子所示,您還可以選擇忽略切片中使用的三個值中的一個或多個值。例如,我在切片 l[0::2] 中沒有使用結束索引。
可變的序列
在本文的開頭,我提到過 list 和 tuple 之間的主要區(qū)別在于 list 是一個可變的序列,這就意味著您不但可以方便地訪問 list 中的條目,而且可以方便地修改它們。但這會引起一個并發(fā)癥狀:您只能修改序列中的條目。若要向序列中添加條目(而不僅僅是修改條目),可使用 append 方法,如清單 5 所示。
清單 5. 修改 list
1
2
3
4
5
6
7
8
9
10
11
|
>>> l = [] >>> l[ 0 ] = 0 # The list is empty Traceback (most recent call last): File "<stdin>" , line 1 , in ? IndexError: list assignment index out of range >>> l.append( 0 ) >>> l [ 0 ] >>> l[ 0 ] = 1 >>> l [ 1 ] |
正如前一個例子所演示的,嘗試修改不存在的 list 條目會導致出現(xiàn)錯誤。這一點意義重大,并演示了 Python 方法生成錯誤的情況。當問題較為嚴重時,將會產(chǎn)生一個錯誤,如果問題較小并且可以很容易地處理,則忽略它。
異構的可變序列
您可能想了解更為復雜的修改。通過綜合切片知識以及如何修改 list 的知識,您應該已經(jīng)獲得了非常重要的見識:可以通過多種方式修改列表。就像 tuple 一樣,list 也可以持有不同類型的數(shù)據(jù)(或不同類型的對象),這就是我所說的異構的可變序列。這兩種功能在清單 6 中進行了更完整的描述。
清單 6. 異構的可變 list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
>>> l = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] >>> l [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] >>> l[ 2 ] = 2 >>> type (l[ 2 ]) < type 'int' > >>> l[ 2 ] = "two" # Change the type of an element >>> ,ype(l[ 2 ]) < type 'str' > >>> l [ 0 , 1 , 'two' , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] >>> l[ 2 ] = l[ 2 : 5 ] * 2 >>> l [ 0 , 1 , [ 'two' , 3 , 4 , 'two' , 3 , 4 ], 3 , 4 , 5 , 6 , 7 , 8 , 9 ] >>> del (l[ 2 ]) # Remove single element >>> l [ 0 , 1 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] >>> l[ 1 : 3 ] = [] # Remove a slice >>> l [ 0 , 4 , 5 , 6 , 7 , 8 , 9 ] |
修改 list 中的條目相當容易:您可以適當?shù)卦O置條目的值,甚至設置成另一種不同的類型,如 string 或另一 list。您還可以使用重復運算符,可以將該運算符識別為乘法運算符,以便從小片段中構建更大的列表。
前面的例子向您展示了如何向 list 中添加元素,以及如何修改 list 中的條目。前一個例子還演示了如何從 list 中刪除對象。刪除條目的第一個方法是使用 del 方法。使用此方法可以刪除一個條目或一個條目范圍。您還可以使用靈活而強大的切片方法從 list 中刪除切片。
數(shù)組
在前一個例子中您可以看到,list 可以包含另一個 list 作為條目。如果擴展此例子,您可能想知道每個條目由一個 list 替換將會發(fā)生什么樣的事情。結果是一個數(shù)組,或者從更加數(shù)學方面來講是一個矩陣。清單 7 展示了如何使用 list 保持二維 (2-D) 或三維 (3-D) 數(shù)組。
清單 7. list 作為一個數(shù)組
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
>>> al = [[ 0 , 1 , 2 ], [ 3 , 4 , 5 ], [ 6 , 7 , 8 ]] >>> al [[ 0 , 1 , 2 ], [ 3 , 4 , 5 ], [ 6 , 7 , 8 ]] >>> al[ 0 ][ 0 ] # First element in 2D array 0 >>> al[ 2 ][ 2 ] # Last element in 2D array 8 >>> al[ 1 ][ 2 ] 5 >>> al = [[[ 0 , 1 ], [ 2 , 3 ]], [[ 4 , 5 ], [ 6 , 7 ]]] >>> al [[[ 0 , 1 ], [ 2 , 3 ]], [[ 4 , 5 ], [ 6 , 7 ]]] >>> al[ 0 ][ 0 ][ 1 ] 1 >>> len (al) # Length of outer dimension 2 >>> len (al[ 0 ]) # Length of middle dimension 2 >>> len (al[ 0 ][ 0 ]) # Length of inner dimension 2 |
其他列表操作
list 對象具有許多可以應用于現(xiàn)有列表的有用方法。例如,您可以反轉(zhuǎn) list 中的所有條目或排序 list。不過,要記住這些操作的一個重點在于,它們是就地 操作,這意味著它們會修改調(diào)用它們所針對的 list。因此,如果您嘗試創(chuàng)建新列表,并將其設置為對這些方法之一調(diào)用所產(chǎn)生的結果,則會得到一個空列表。
list 除可以用于模擬數(shù)組外,還可以用于模擬其他數(shù)據(jù)結構。例如,append 和 pop 方法對 list 函數(shù)的操作要么是先進先出 (FIFO) 數(shù)據(jù)結構(也稱為隊列),要么是后進先出 (LIFO) 數(shù)據(jù)結構(也稱為堆棧)。通過允許您將條目設置為從 list 中彈出(刪除并返回),pop 方法支持這些功能。如果彈出 list 的第一項,則是一個隊列;反之,如果彈出 list 的最后一項,則是一個堆棧,如清單 8 所示。
清單 8. 操縱 list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
>>> l = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] >>> id (l) # This is the object id for our current list 4525432 >>> l.reverse() # Reverse the list >>> l [ 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ] >>> id (l) # The id is the same, modified list in place. 4525432 >>> l.sort() # Sort the list in numerical order >>> l [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] >>> id (l) # Modified the existing list 4525432 >>> l.index( 5 ) # Same as l[5] 5 >>> l.count( 0 ) # How many times does '0' occur in the list 1 >>> l.pop() # Take off the last item (Stack) 9 >>> l [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] >>> l.pop( 5 ) # Take out the fifth element 5 >>> l [ 0 , 1 , 2 , 3 , 4 , 6 , 7 , 8 ] >>> l.pop( 0 ) # Take the first item off the list (Queue) 0 >>> l [ 1 , 2 , 3 , 4 , 6 , 7 , 8 ] |
列表:切片和切塊
本文介紹了 list,它是一個容器對象,可以方便地進行修改,而且可以持有不同類型的數(shù)據(jù)。由于它具有相當?shù)撵`活性,因此 list 是 Python 編程語言中最常用的結構之一已不足為怪。list 像一個口袋,可以容納不同類型的數(shù)據(jù),并可以根據(jù)需要更改。您可以像使用數(shù)組一樣使用 list,以有組織的方式容納數(shù)據(jù);您還可以像使用隊列或堆棧一樣使用 list。在以后的文章中還將更為深入地探索這一靈活性,并介紹強大的編程技術,即列表理解。