1. 程式人生 > 遊戲攻略 >《原神攻略》無甘雨低配永凍流隊伍搭配參考

《原神攻略》無甘雨低配永凍流隊伍搭配參考

列表和元組

在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'

如你所見,切片適用於提取序列的一部分,其中的編號非常重要:第一個索引是包含的第一
個元素的編號,但第二個索引是切片後餘下的第一個元素的編號。
簡而言之,你提供兩個索引來指定切片的邊界,其中第一個索引指定的元素包含在切片內,
但第二個索引指定的元素不包含在切片內。

    1. 絕妙的簡寫
      假設你要訪問前述數字列表中的最後三個元素,顯然可以明確地指定這一點。
>>> 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. 更大的步長
      執行切片操作時,你顯式或隱式地指定起點和終點,但通常省略另一個引數,即步長。在普
      通切片中,步長為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來檢查指定的字串是否為另一個字
符串的子串。