一個list是按_順序_排列項目的可變集合。就像大多數集合(請看內建的tuple、dict和set)一樣,陣列可以存放任何(或多種)資料型態的參照,包括其他陣列。在 Python 中,它們被視為一種序列,可以透過切片語法整份或部分複製。和任何序列一樣,lists中的元素可以從左側以0-based index編號引用,也可以從右側以-1-based index編號引用。
陣列同時支援常見與可變的序列操作,例如min(<list>)/max(<list>)、<list>.index()、<list>.append()和<list>.reverse()。項目可以使用for item in <list>結構來疊代,而當元素和元素索引都需要時,則使用for index, item in enumerate(<list>)。
Python 提供了許多實用的方法來處理陣列。
因為陣列是可變的,陣列方法會改動傳入方法中的原始陣列物件。如果不希望改動,就必須透過slice或<list>.copy(),對原始list製作一份(至少是)shallow copy。
可以使用<list>.append(<item>)把項目加到現有陣列的尾端:
>>> numbers = [1, 2, 3]
>>> numbers.append(9)
>>> numbers
[1, 2, 3, 9]
<list>.insert(<index>, <item>)不是_附加_,而是把項目加到陣列中_特定的索引_。<index>是你希望新項目出現在它_之前_的那個項目的索引,<item>則是要插入的元素。
注意:如果<index>是 0,項目會加到陣列的開頭。如果<index>大於陣列的最後一個索引,項目會加到最末的位置,等同於使用<list>.append(<item>)。
>>> numbers = [1, 2, 3]
>>> numbers.insert(0, -2)
>>> numbers
[-2, 1, 2, 3]
>>> numbers.insert(1, 0)
>>> numbers
[-2, 0, 1, 2, 3]
可以透過<list>.extend(<iterable>)把iterable與現有的陣列_合併_(將兩者串接)。<list>.extend(<iterable>)會_拆解_傳入的 iterable,並依相同順序把它的元素加到目標陣列的尾端。在這種情況下改用<list>.append(<item>),會把整個 iterable 當成_單一項目_加入。
>>> numbers = [1, 2, 3]
>>> other_numbers = [5, 6, 7]
>>> numbers.extend(other_numbers)
>>> numbers
[1, 2, 3, 5, 6, 7]
>>> numbers.extend([8, 9])
>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9]
可以使用<list>.remove(<item>)從陣列中移除元素。如果元素不存在於陣列中,<list>.remove(<item>)會擲出ValueError。
>>> numbers = [1, 2, 3]
>>> numbers.remove(2)
>>> numbers
[1, 3]
# Trying to remove a value that is not in the list throws a ValueError.
>>> numbers.remove(0)
ValueError: list.remove(x): x not in list
或者,使用<list>.pop(<index>)方法會同時移除並return一個元素供使用。
<list>.pop(<index>)接受一個選用參數:要移除並回傳之元素的index。如果沒有指定選用的<index>引數,就會移除並回傳陣列的最後一個元素。如果<index>的數字大於陣列的最後一個索引,就會擲出IndexError。
>>> numbers = [1, 2, 3]
>>> numbers.pop(0)
1
>>> numbers
[2, 3]
>>> numbers.pop()
3
>>> numbers
[2]
# This will throw an error because there is only index 0.
>>> numbers.pop(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop index out of range
可以透過<list>.clear()移除list中的所有項目。它不接受任何參數。
>>> numbers = [1, 2, 3]
>>> numbers.clear()
>>> numbers
[]
可以使用<list>.reverse()_就地_反轉陣列元素的順序。這會改動原始陣列。
>>> numbers = [1, 2, 3]
>>> numbers.reverse()
>>> numbers
[3, 2, 1]
可以藉助<list>.sort()_就地重新排序陣列。預設的排序順序是從左側_遞增。Python 文件提供了更多排序技巧與方法。
從 2002 到 2022 年,Python 內部使用一個稱為Timsort的演算法來排列陣列,但從Python 3.11起改用Powersort。你可以在 GitHub 的議題 78742中,閱讀 Python 核心團隊關於這項變更的更多細節與討論。
如需該演算法的技術細節,請參閱 J. Ian Munro 與 Sebastian Wild 的論文 Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally Adapt to Existing Runs
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
# The default sort order is *ascending*.
>>> names.sort()
>>> names
["Bruce", "Natasha", "Thor", "Tony"]
若要依_遞減_順序排序陣列,請把reverse=True引數傳給該方法:
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
>>> names.sort(reverse=True)
>>> names
["Tony", "Thor", "Natasha", "Bruce"]
如果不想改動原始list,可以使用內建函式sorted()和reversed()。sorted(<list>)會回傳排序後的_副本_,並接受與<list>.sort()相同的參數。reversed(<list>)會回傳一個_疊代器_,以相反的順序產生陣列的項目。Iterators會在另一個練習中詳細介紹。
可以藉由<list>.count(<item>)找出某個元素在陣列中出現的次數。它會回傳<item>以元素身分出現在陣列中的總次數。
>>> items = [1, 4, 7, 8, 2, 9, 2, 1, 1, 0, 4, 3]
>>> items.count(1)
3
<list>.index(<item>)會回傳傳入項目_第一次出現_的索引編號。如果都沒有出現,就會引發ValueError。從左側索引是0-based,也就是第一個項目的位置是索引0。也支援從右側索引,從索引-1開始。
>>> items = [7, 4, 1, 0, 2, 5]
>>> items.index(4)
1
>>> items.index(10)
ValueError: 10 is not in list
提供start和end索引,就會在陣列中的特定區段內搜尋:
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> names.index("Tina")
0
>>> names.index("Tina", 2, 5)
3
如果不需要元素確切的位置,使用內建的in運算子來驗證成員資格會更有效率。
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> "Thomas" in names
True
請記住,Python 中的變數是指向底層物件的名稱。名稱在程式執行期間可以綁定或重新綁定到不同的物件。把一個list物件指定給新的變數_名稱,並不會複製該物件或它所參照的任何資料。新名稱和舊名稱都會指向同一個list物件。此外,陣列是_容器_型態的物件:為了節省空間,容器只持有成員項目的_參照,而不是項目本身。這種「最佳化」對不經心的人可能造成意想不到的後果。
<list>.copy()會建立一個新的list物件,但不會為所參照的陣列_元素_建立新物件,這種複本算是「淺層」的。當你想在其中一個list物件新增或移除項目,而不想改動另一個時,shallow copy通常就夠用了。但如果list的_底層元素_有可能被意外改動(因而連帶改動所有相關的淺層複本),就應該使用copy模組中的copy.deepcopy(),為所有參照與物件建立完整或「深層」的複本。
如果想詳細了解名稱、值、陣列和巢狀陣列的行為,請看看 Ned Batchelder 的這篇精彩部落格文章:Names and values: making a game board。Shallow vs Deep Copying of Python Objects 也對複製的各種考量做了很好的整理。