《原神攻略》無甘雨低配永凍流隊伍搭配參考
列表和元組
在Python中,最基本的資料結構為序列(sequence)。
序列中的每個元素都有編號,即其位置或索引,其中第一個元素的索引為0,第二個元素的索引
為1,依此類推。
但從0開始指出相對於序列
開頭的偏移量。這顯得更自然,同時可迴繞到序列末尾,用負索引表示序列末尾元素的位置。你
可能認為這種編號方式有點怪,但我敢肯定,你很快就會習慣的。
元組是一種特殊的序列,類
似於列表,只是不能修改。
2.1 序列概述
Python內建了多種序列,本章重點討論其中最常用的兩種:列表和元組。另一種重要的序列
是字串,將在下一章更詳細地討論。
列表和元組的主要不同在於,列表是可以修改的,而元組不可以。這意味著列表適用於需要
中途新增元素的情形,而元組適用於出於某種考慮需要禁止修改序列的情形。禁止修改序列通常
出於技術方面的考慮,與Python的內部工作原理相關,這也是有些內建函式返回元組的原因所在。
在你自己編寫程式時,幾乎在所有情況下都可使用列表來代替元組。一種例外情況是將元組用作
字典鍵,這將在第4章討論。在這種情況下,不能使用列表來代替元組,因為字典鍵是不允許修
改的。
在需要處理一系列值時,序列很有用。在資料庫中,你可能使用序列來表示人,其中第一個
元素為姓名,而第二個元素為年齡。如果使用列表來表示(所有元素都放在方括號內,並用逗號
隔開),將類似於下面這樣:
>>> edward = ['Edward Gumby', 42]
序列還可包含其他序列,因此可建立一個由資料庫中所有人員組成的列表:
>>> edward = ['Edward Gumby', 42]
>>> john = ['John Smith', 50]
>>> database = [edward, john]
>>> database
[['Edward Gumby', 42], ['John Smith', 50]]
Python支援一種資料結構的基本概念,名為容器(container)。容器基本上就是可包含其
他物件的物件。兩種主要的容器是序列(如列表和元組)和對映(如字典)。在序列中,
每個元素都有編號,而在對映中,每個元素都有名稱(也叫鍵)。對映將在第4章詳細討
論。有一種既不是序列也不是對映的容器,它就是集合(set),將在第10章討論。
2.2 通用的序列操作
有幾種操作適用於所有序列,包括索引、切片、相加、相乘和成員資格檢查。另外,Python
還提供了一些內建函式,可用於確定序列的長度以及找出序列中最大和最小的元素。
有一個重要的操作這裡不會介紹,它就是迭代(iteration)。對序列進行迭代意味著對其
每個元素都執行特定的操作。有關迭代的詳細資訊,請參閱5.5節。
2.2.1 索引
不同於其他一
些語言,Python沒有專門用於表示字元的型別,因此一個字元就是隻包含一個元素的字
符串。
這稱為索引(indexing)。你可使用索引來獲取元素。這種索引方式適用於所有序列。當你使
用負數索引時,Python將從右(即從最後一個元素)開始往左數,因此1是最後一個元素的位置。
對於字串字面量(以及其他的序列字面量),可直接對其執行索引操作,無需先將其賦給
變數。這與先賦給變數再對變數執行索引操作的效果是一樣的。
>>> 'Hello'[1]
'e'
如果函式呼叫返回一個序列,可直接對其執行索引操作。例如,如果你只想獲取使用者輸入的
年份的第4位,可像下面這樣做:
>>> fourth = input('Year: ')[3]
Year: 2005
>>> fourth
'5'
# 將以數指定年、月、日的日期打印出來
months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
]
# 一個列表,其中包含數1~31對應的結尾
endings = ['st', 'nd', 'rd'] + 17 * ['th'] \
+ ['st', 'nd', 'rd'] + 7 * ['th'] \
+ ['st']
year = input('Year: ')
month = input('Month (1-12): ')
day = input('Day (1-31): ')
month_number = int(month)
day_number = int(day)
# 別忘了將表示月和日的數減1,這樣才能得到正確的索引
month_name = months[month_number-1]
ordinal = day + endings[day_number-1]
print(month_name + ' ' + ordinal + ', ' + year)
這個程式的執行情況類似於下面這樣:
Year: 1974
Month (1-12): 8
Day (1-31): 16
August 16th, 1974
2.2.2 切片
除使用索引來訪問單個元素外,還可使用切片(slicing)來訪問特定範圍內的元素。為此,
可使用兩個索引,並用冒號分隔:
>>> tag = '<a href="http://www.python.org">Python web site</a>'
>>> tag[9:30]
'http://www.python.org'
>>> tag[32:-4]
'Python web site'
如你所見,切片適用於提取序列的一部分,其中的編號非常重要:第一個索引是包含的第一
個元素的編號,但第二個索引是切片後餘下的第一個元素的編號。
簡而言之,你提供兩個索引來指定切片的邊界,其中第一個索引指定的元素包含在切片內,
但第二個索引指定的元素不包含在切片內。
-
- 絕妙的簡寫
假設你要訪問前述數字列表中的最後三個元素,顯然可以明確地指定這一點。
- 絕妙的簡寫
>>> numbers[7:10]
[8, 9, 10]
在這裡,索引10指的是第11個元素:它並不存在,但確實是到達最後一個元素後再前進一步
所處的位置。明白了嗎?如果要從列表末尾開始數,可使用負數索引。
>>> numbers[-3:-1]
[8, 9]
然而,這樣好像無法包含最後一個元素。如果使用索引0,即到達列表末尾後再前進一步所
處的位置,結果將如何呢?
>>> numbers[-3:0]
[]
結果並不是你想要的。事實上,執行切片操作時,如果第一個索引指定的元素位於第二個索
引指定的元素後面(在這裡,倒數第3個元素位於第1個元素後面),結果就為空序列。好在你能
使用一種簡寫:如果切片結束於序列末尾,可省略第二個索引。
>>> numbers[-3:]
[8, 9, 10]
同樣,如果切片始於序列開頭,可省略第一個索引。
>>> numbers[:3]
[1, 2, 3]
實際上,要複製整個序列,可將兩個索引都省略。
>>> numbers[:]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-
- 更大的步長
執行切片操作時,你顯式或隱式地指定起點和終點,但通常省略另一個引數,即步長。在普
通切片中,步長為1。這意味著從一個元素移到下一個元素,因此切片包含起點和終點之間的所
有元素。
- 更大的步長
>>> numbers[0:10:1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
在這個示例中,指定了另一個數。你可能猜到了,這顯式地指定了步長。如果指定的步長大
於1,將跳過一些元素。例如,步長為2時,將從起點和終點之間每隔一個元素提取一個元素。
>>> numbers[0:10:2]
[1, 3, 5, 7, 9]
numbers[3:6:3]
[4]
顯式地指定步長時,也可使用前述簡寫。例如,要從序列中每隔3個元素提取1個,只需提供
步長4即可。
>>> numbers[::4]
[1, 5, 9]
當然,步長不能為0,否則無法向前移動,但可以為負數,即從右向左提取元素。
>>> numbers[8:3:-1]
[9, 8, 7, 6, 5]
>>> numbers[10:0:-2]
[10, 8, 6, 4, 2]
>>> numbers[0:10:-2]
[]
>>> numbers[::-2]
[10, 8, 6, 4, 2]
>>> numbers[5::-2]
[6, 4, 2]
>>> numbers[:5:-2]
[10, 8]
在這種情況下,要正確地提取頗費思量。如你所見,第一個索引依然包含在內,而第二個索
引不包含在內。步長為負數時,第一個索引必須比第二個索引大。可能有點令人迷惑的是,當你
省略起始和結束索引時,Python竟然執行了正確的操作:步長為正數時,它從起點移到終點,而
步長為負數時,它從終點移到起點。
2.2.3 序列相加
可使用加法運算子來拼接序列。
>>> [1, 2, 3] + [4, 5, 6]
[1, 2, 3, 4, 5, 6]
>>> 'Hello,' + 'world!'
'Hello, world!'
>>> [1, 2, 3] + 'world!'
Traceback (innermost last):
File "<pyshell>", line 1, in ?
[1, 2, 3] + 'world!'
TypeError: can only concatenate list (not "string") to list
從錯誤訊息可知,不能拼接列表和字串,雖然它們都是序列。一般而言,不能拼接不同類
型的序列。
2.2.4 乘法
將序列與數x相乘時,將重複這個序列x次來建立一個新序列:
>>> 'python' * 5
'pythonpythonpythonpythonpython'
>>> [42] * 10
[42, 42, 42, 42, 42, 42, 42, 42, 42, 42]
None、空列表和初始化
空列表是使用不包含任何內容的兩個方括號([])表示的。如果要建立一個可包含10個元素
的列表,但沒有任何有用的內容,可像前面那樣使用[42]10。但更準確的做法是使用[0]10,
這將建立一個包含10個零的列表。然而,在有些情況下,你可能想使用表示“什麼都沒有”的值,
如表示還沒有在列表中新增任何內容。在這種情況下,可使用None。在Python中,None表示什麼
都沒有。因此,要將列表的長度初始化為10,可像下面這樣做:
>>> sequence = [None] * 10
>>> sequence
[None, None, None, None, None, None, None, None, None, None]
程式碼清單2-3所示的程式在螢幕上列印一個由字元組成的方框。這個方框位於螢幕中央,寬
度取決於使用者提供的句子的長度。這些程式碼看似很複雜,但基本上只使用了算術運算:計算需要
多少個空格、短劃線等,以便將內容顯示到正確的位置。
2.2.5 成員資格
要檢查特定的值是否包含在序列中,可使用運算子in。這個運算子與前面討論的運算子(如
乘法或加法運算子)稍有不同。它檢查是否滿足指定的條件,並返回相應的值:滿足時返回True,
不滿足時返回False。這樣的運算子稱為布林運算子,而前述真值稱為布林值。布林表示式將在
5.4節詳細介紹。
下面是一些in運算子的使用示例:
>>> permissions = 'rw'
>>> 'w' in permissions
True
>>> 'x' in permissions
False
>>> users = ['mlh', 'foo', 'bar']
>>> input('Enter your user name: ') in users
Enter your user name: mlh
True
>>> subject = '$$$ Get rich now!!! $$$'
>>> '$$$' in subject
True
開頭兩個示例使用成員資格測試分別檢查'w'和'x'是否包含在字串變數permissions中。在
UNIX系統中,可在指令碼中使用這兩行程式碼來檢查對檔案的寫入和執行許可權。接下來的示例檢查
提供的使用者名稱mlh是否包含在使用者列表中,這在程式需要執行特定的安全策略時很有用(在這種
情況下,可能還需檢查密碼)。最後一個示例檢查字串變數subject是否包含字串'$$$',這
可用於垃圾郵件過濾器中。
相比於其他示例,檢查字串是否包含'$$$'的示例稍有不同。一般而言,運算子in檢查
指定的物件是否是序列(或其他集合)的成員(即其中的一個元素),但對字串來說,
只有它包含的字元才是其成員或元素,因此下面的程式碼完全合理:
>>> 'P' in 'Python'
True
事實上,在較早的Python版本中,只能對字串執行這種成員資格檢查——確定指定的
字元是否包含在字串中,但現在可使用運算子in來檢查指定的字串是否為另一個字
符串的子串。