非程式設計師的 Python 3 教程/更多關於列表
我們已經看到了列表以及如何使用它們。現在您已經瞭解了一些背景知識,我將詳細介紹列表。首先,我們將研究更多訪問列表中元素的方法,然後我們將討論如何複製它們。
以下是一些使用索引訪問列表單個元素的示例
>>> some_numbers = ['zero', 'one', 'two', 'three', 'four', 'five'] >>> some_numbers[0] 'zero' >>> some_numbers[4] 'four' >>> some_numbers[5] 'five'
所有這些示例都應該很熟悉。如果您想要列表中的第一個專案,只需檢視索引 0。第二個專案是索引 1,依此類推。但是,如果您想要列表中的最後一個專案呢?一種方法是使用 len() 函式,例如 some_numbers[len(some_numbers) - 1]。這種方法有效,因為 len() 函式始終返回最後一個索引加一。倒數第二個將是 some_numbers[len(some_numbers) - 2]。有一種更簡單的方法。在 Python 中,最後一個專案始終是索引 -1。倒數第二個是索引 -2,依此類推。以下是一些更多示例
>>> some_numbers[len(some_numbers) - 1] 'five' >>> some_numbers[len(some_numbers) - 2] 'four' >>> some_numbers[-1] 'five' >>> some_numbers[-2] 'four' >>> some_numbers[-6] 'zero'
因此,列表中的任何專案都可以用兩種方式索引:從前面和從後面。
另一種訪問列表部分的有用方法是使用切片。以下是一個示例,讓您瞭解它們的用途
>>> things = [0, 'Fred', 2, 'S.P.A.M.', 'Stocking', 42, "Jack", "Jill"] >>> things[0] 0 >>> things[7] 'Jill' >>> things[0:8] [0, 'Fred', 2, 'S.P.A.M.', 'Stocking', 42, 'Jack', 'Jill'] >>> things[2:4] [2, 'S.P.A.M.'] >>> things[4:7] ['Stocking', 42, 'Jack'] >>> things[1:5] ['Fred', 2, 'S.P.A.M.', 'Stocking']
切片用於返回列表的一部分。切片運算子的形式為 things[first_index:last_index]。切片在 first_index 之前和 last_index 之前切割列表,並返回兩者之間的部分。您可以使用兩種型別的索引
>>> things[-4:-2] ['Stocking', 42] >>> things[-4] 'Stocking' >>> things[-4:6] ['Stocking', 42]
切片中的另一個技巧是未指定的索引。如果未指定第一個索引,則假定為列表的開頭。如果未指定最後一個索引,則假定為列表的剩餘部分。以下是一些示例
>>> things[:2] [0, 'Fred'] >>> things[-2:] ['Jack', 'Jill'] >>> things[:3] [0, 'Fred', 2] >>> things[:-5] [0, 'Fred', 2]
這是一個(受 HTML 啟發的)程式示例(如果您需要,請複製並貼上到詩歌定義中)
poem = ["<B>", "Jack", "and", "Jill", "</B>", "went", "up", "the",
"hill", "to", "<B>", "fetch", "a", "pail", "of", "</B>",
"water.", "Jack", "fell", "<B>", "down", "and", "broke",
"</B>", "his", "crown", "and", "<B>", "Jill", "came",
"</B>", "tumbling", "after"]
def get_bold(text):
true = 1
false = 0
## is_bold tells whether or not we are currently looking at
## a bold section of text.
is_bold = false
## start_block is the index of the start of either an unbolded
## segment of text or a bolded segment.
start_block = 0
for index in range(len(text)):
## Handle a starting of bold text
if text[index] == "<B>":
if is_bold:
print("Error: Extra Bold")
## print "Not Bold:", text[start_block:index]
is_bold = true
start_block = index + 1
## Handle end of bold text
## Remember that the last number in a slice is the index
## after the last index used.
if text[index] == "</B>":
if not is_bold:
print("Error: Extra Close Bold")
print("Bold [", start_block, ":", index, "]", text[start_block:index])
is_bold = false
start_block = index + 1
get_bold(poem)
輸出為
Bold [ 1 : 4 ] ['Jack', 'and', 'Jill'] Bold [ 11 : 15 ] ['fetch', 'a', 'pail', 'of'] Bold [ 20 : 23 ] ['down', 'and', 'broke'] Bold [ 28 : 30 ] ['Jill', 'came']
get_bold() 函式接受一個列表,該列表被分解為單詞和標記。它查詢的標記是 <B>(開始粗體文字)和 </B>(結束粗體文字)。get_bold() 函式會遍歷並搜尋開始和結束標記。
列表的下一個功能是複製它們。如果您嘗試像這樣簡單的事情
>>> a = [1, 2, 3] >>> b = a >>> print(b) [1, 2, 3] >>> b[1] = 10 >>> print(b) [1, 10, 3] >>> print(a) [1, 10, 3]
這看起來可能令人驚訝,因為對 b 的修改也導致了 a 的更改。發生的事情是,語句 b = a 使 b 成為 a 的引用。這意味著可以將 b 視為 a 的另一個名稱。因此,對 b 的任何修改也會更改 a。但是,有些賦值不會為一個列表建立兩個名稱
>>> a = [1, 2, 3] >>> b = a * 2 >>> print(a) [1, 2, 3] >>> print(b) [1, 2, 3, 1, 2, 3] >>> a[1] = 10 >>> print(a) [1, 10, 3] >>> print(b) [1, 2, 3, 1, 2, 3]
在這種情況下,b 不是 a 的引用,因為表示式 a * 2 建立了一個新列表。然後,語句 b = a * 2 使 b 成為 a * 2 的引用,而不是 a 的引用。所有賦值操作都會建立引用。當您將列表作為引數傳遞給函式時,您也會建立引用。大多數時候,您不必擔心建立引用而不是副本。但是,當您需要修改一個列表而不更改另一個列表名稱時,您必須確保您實際上建立了一個副本。
有幾種方法可以製作列表的副本。最簡單的方法是使用切片運算子,因為它始終建立一個新列表,即使它是一個完整列表的切片
>>> a = [1, 2, 3] >>> b = a[:] >>> b[1] = 10 >>> print(a) [1, 2, 3] >>> print(b) [1, 10, 3]
獲取切片 [:] 會建立一個列表的新副本。但是,它只複製外部列表。內部的任何子列表仍然是對原始列表中子列表的引用。因此,當列表包含列表時,內部列表也必須被複制。您可以手動執行此操作,但 Python 已經包含一個模組來執行此操作。您可以使用 copy 模組的 deepcopy 函式
>>> import copy >>> a = [[1, 2, 3], [4, 5, 6]] >>> b = a[:] >>> c = copy.deepcopy(a) >>> b[0][1] = 10 >>> c[1][1] = 12 >>> print(a) [[1, 10, 3], [4, 5, 6]] >>> print(b) [[1, 10, 3], [4, 5, 6]] >>> print(c) [[1, 2, 3], [4, 12, 6]]
首先請注意,a 是一個列表的列表。然後請注意,當執行 b[0][1] = 10 時,a 和 b 都被更改,但 c 沒有被更改。發生這種情況是因為當使用切片運算子時,內部陣列仍然是引用。但是,使用 deepcopy,c 被完全複製。
那麼,我是否應該在每次使用函式或 = 時都擔心引用?好訊息是,您只需要在使用字典和列表時才擔心引用。數字和字串在賦值時建立引用,但對數字和字串的每個修改操作都會建立一個新副本,因此您永遠不會意外地修改它們。在修改列表或字典時,您確實需要考慮引用。
到目前為止,您可能想知道為什麼在所有情況下都要使用引用?基本原因是速度。建立對包含一千個元素的列表的引用比複製所有元素要快得多。另一個原因是它允許您有一個函式來修改輸入的列表或字典。只要記住關於引用,如果您遇到資料在不應該更改時被更改的奇怪問題。