在講解列表和元組之前,本節(jié)先介紹Python中序列的通用操作,這些操作在列表和元組中都會(huì)用到。
Python中所有序列都可以進(jìn)行一些特定操作,包括索引(indexing)、分片(slicing)、序列相加(adding)、乘法(multiplying)、成員資格、長(zhǎng)度、最小值和最大值。
通用序列操作:
1.索引
序列是Python中最基本的數(shù)據(jù)結(jié)構(gòu)。序列中的每個(gè)元素都分配一個(gè)數(shù)字,代表它在序列中的位置(索引),第一個(gè)索引是0,第二個(gè)索引是1,以此類(lèi)推。
序列中所有元素都是有編號(hào)的,從0開(kāi)始遞增??梢酝ㄟ^(guò)編號(hào)分別對(duì)序列的元素進(jìn)行訪(fǎng)問(wèn)。下面通過(guò)交互輸入方式介紹一個(gè)通過(guò)編號(hào)取元素的例子。
>>> greeting='Hello'#定義變量greeting,并賦值Hello
>>> greeting[0] #根據(jù)編號(hào)取元素,使用格式為:在中括號(hào)中輸入所取元素的編號(hào)值
'H'
>>> greeting[1]
'e'
>>> greeting[2]
'l'
可以看到,序列中的元素從0開(kāi)始,從左向右依自然順序編號(hào),元素可以通過(guò)編號(hào)訪(fǎng)問(wèn)。獲取元素的方式為:在變量后加中括號(hào),在中括號(hào)中輸入所取元素的編號(hào)值。這個(gè)格式需要記住。
類(lèi)似于我們平時(shí)排隊(duì),站成一排時(shí),一般從左往右編號(hào),編上序號(hào)后(一般從1開(kāi)始編號(hào),不會(huì)從0開(kāi)始),當(dāng)叫一個(gè)序號(hào)時(shí),就會(huì)由序號(hào)對(duì)應(yīng)到人。程序中的序列也是如此。
這里的編號(hào)就是索引,可以通過(guò)索引獲取元素。所有序列都可以通過(guò)這種方式進(jìn)行索引。
注意:字符串是由字符組成的序列。索引0指向第一個(gè)元素。比如在上面的示例中,索引0指向字母H,索引1指向字母e,索引2指向字母l。
上面的示例是從左往右通過(guò)編號(hào)獲取元素的,是否可以從右往左通過(guò)編號(hào)獲取元素呢?我們?cè)囈辉?,在交互模式下輸入?/p>
>>> greeting[-1]
'o'
>>> greeting[-2]
'l'
>>> greeting[-3]
'l'
>>> greeting[-4]
'e'
可以看到,Python的序列也可以從右開(kāi)始索引,最右邊的元素索引值為-1,從右向左遞減。
在Python中,從左向右索引稱(chēng)為正數(shù)索引,從右向左索引稱(chēng)為負(fù)數(shù)索引。使用負(fù)數(shù)索引時(shí),Python會(huì)從最后一個(gè)元素開(kāi)始計(jì)數(shù)。最后一個(gè)元素的位置編號(hào)是-1。
注意:最后一個(gè)元素的編號(hào)不是-0,跟數(shù)學(xué)中的概念一樣,-0=0、-0和0都指向第一個(gè)元素。
從上面的幾個(gè)示例可以看到,進(jìn)行字符串的索引時(shí)都定義了一個(gè)變量,其實(shí)不定義變量也可以。下面來(lái)看一個(gè)例子,在交互模式輸入:
>>> 'Hello'[0]
'H'
>>> 'Hello'[1]
'e'
>>> 'Hello'[-1]
'o'
>>> 'Hello'[-2]
'l'
可以看到,直接使用索引,不定義變量進(jìn)行引用也可以。直接使用索引的效果和定義變量的效果是一樣的。
如果函數(shù)返回一個(gè)序列,是否可以直接對(duì)結(jié)果進(jìn)行索引操作呢?在交互模式下輸入:
>>> thirdth=input()[0]
happy
>>> thirdth
'h'
由輸出結(jié)果可以看到,直接對(duì)函數(shù)的返回結(jié)果進(jìn)行了索引操作。
索引既可以對(duì)變量的引用操作,也可以直接操作序列,還可以操作函數(shù)的返回序列。
2.分片
索引用來(lái)對(duì)單個(gè)元素進(jìn)行訪(fǎng)問(wèn),使用分片可以對(duì)一定范圍內(nèi)的元素進(jìn)行訪(fǎng)問(wèn),分片通過(guò)冒號(hào)相隔的兩個(gè)索引實(shí)現(xiàn)。在交互模式輸入:
>>> number=[1,2,3,4,5,6,7,8,9,10]
>>> number[1:3] #取索引為第一和第二的元素
[2, 3]
>>> number[-3:-1] #負(fù)數(shù)表明從右開(kāi)始計(jì)數(shù),取得倒數(shù)第三和倒數(shù)第二的元素
[8, 9]
由操作結(jié)果可以看到,分片操作既支持正數(shù)索引,也支持負(fù)數(shù)索引,并且對(duì)于提取序列的一部分很方便。
分片操作的實(shí)現(xiàn)需要提供兩個(gè)索引作為邊界,第一個(gè)索引的元素包含在分片內(nèi),第二個(gè)索引的元素不包含在分片內(nèi)。像數(shù)學(xué)里的a≤x<b,x是我們需要得到的元素,a是分片操作中的第一個(gè)索引,b是第二個(gè)索引,b不包含在x的范圍內(nèi)。
對(duì)于上面的示例,假設(shè)需要訪(fǎng)問(wèn)最后3個(gè)元素,使用正數(shù)索引可以這樣操作:
>>> number=[1,2,3,4,5,6,7,8,9,10]
>>> number[7:10] #取最后3 個(gè)元素
[8, 9, 10]
由以上輸入和我們前面對(duì)序列的定義可以得出,number的編號(hào)最大應(yīng)該為9,編號(hào)為10指向的是第11個(gè)元素,是一個(gè)不存在的元素,但是由于在最后一個(gè)元素之后,因此能得到最后一個(gè)元素。這么做沒(méi)問(wèn)題。如果需要從列表的結(jié)尾開(kāi)始,即使用負(fù)數(shù)索引,怎么辦呢?我們嘗試看看,輸入如下:
>>> number=[1,2,3,4,5,6,7,8,9,10]
>>> number[-3,-1]
[8, 9]
結(jié)果沒(méi)有輸出最后一個(gè)元素。再試試使用索引0作為最后一個(gè)元素的下一個(gè)元素,輸入如下:
>>> number[-3:0]
[]
這個(gè)輸出結(jié)果有點(diǎn)奇怪,竟然一個(gè)數(shù)值都沒(méi)有。
事實(shí)上,只要在分片中最左邊的索引比它右邊的索引晚出現(xiàn)在序列中,結(jié)果就是一個(gè)空序列。比如上例中,-3代表倒數(shù)第3個(gè)元素,0代表第一個(gè)元素,倒數(shù)第3個(gè)元素比第一個(gè)元素晚出現(xiàn),即排在第一個(gè)元素后面,所以得到的結(jié)果是空序列。
我們?cè)趺赐ㄟ^(guò)負(fù)數(shù)索引的方式取得最后一個(gè)元素呢?這里有一個(gè)捷徑可以使用。如果需要取得的分片包括序列結(jié)尾的元素,只需將第二個(gè)索引設(shè)置為空即可。輸入如下:
>>> number[-3:]
[8, 9, 10]
輸出結(jié)果和我們預(yù)期的一樣。
正數(shù)索引能否使用這種方式呢?輸入如下:
>>> number[0:] #從第一個(gè)元素開(kāi)始輸出,輸出全部結(jié)果
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> number[:0] #最后一個(gè)元素為第一個(gè),輸出為空
[]
>>> number[:3] #取得前3 個(gè)元素
[1, 2, 3]
由輸出結(jié)果可以知道也適用于正數(shù)索引。
根據(jù)上述輸出結(jié)果可知,若需要輸出整個(gè)序列,則可以將兩個(gè)索引都設(shè)置為空。輸入如下:
>>> number[:] #取得整個(gè)數(shù)組
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
輸出結(jié)果是整個(gè)序列。
進(jìn)行分片時(shí),分片的開(kāi)始和結(jié)束點(diǎn)都需要指定(無(wú)論是直接還是間接),用這種方式取連續(xù)的元素沒(méi)有問(wèn)題,但若要取序列中不連續(xù)的元素就比較麻煩,或者直接不能操作。比如要取序列number中的所有奇數(shù),以一個(gè)序列展示出來(lái),用前面的方法就不能實(shí)現(xiàn)了。
對(duì)于上面這種情況,Python為我們提供了另一個(gè)參數(shù)——步長(zhǎng)(step length),該參數(shù)通常是隱式設(shè)置的。在普通分片中,步長(zhǎng)是1。分片操作就是按照這個(gè)步長(zhǎng)逐個(gè)遍歷序列的元素,遍歷后返回開(kāi)始和結(jié)束點(diǎn)之間的所有元素。也可以理解為默認(rèn)步長(zhǎng)是1,即沒(méi)有設(shè)置步長(zhǎng)時(shí),步長(zhǎng)隱式設(shè)置值為1。輸入如下:
>>> number[0:10:1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
由上面的示例可以看到,分片包含另一個(gè)數(shù)字。這種方式就是步長(zhǎng)的顯式設(shè)置。看起來(lái)和隱式設(shè)置步長(zhǎng)沒(méi)什么區(qū)別,得到結(jié)果和之前也一樣。但若將步長(zhǎng)設(shè)置為比1大的數(shù),結(jié)果會(huì)怎樣呢?輸入如下:
>>> number[0:10:2]
[1, 3, 5, 7, 9]
由上面的輸出結(jié)果可以看到,對(duì)于number序列,設(shè)置步長(zhǎng)為2時(shí),得到的結(jié)果就是我們前面想要的奇數(shù)序列。
由結(jié)果可知,步長(zhǎng)設(shè)置為大于1的數(shù)時(shí),會(huì)得到一個(gè)跳過(guò)某些元素的序列。例如,我們上面設(shè)置的步長(zhǎng)為2,得到的序列是從開(kāi)始到結(jié)束每隔1個(gè)元素的序列。比如還可以這樣使用:
>>> number[0:10:3]
[1, 4, 7, 10]
>>> number[2:6:3]
[3, 6]
>>> number[2:5:3]
[3]
>>> number[1:5:3]
[2, 5]
由以上輸出可以看到,使用步長(zhǎng)的方式還是很靈活的。
除了上面的使用方式外,設(shè)置前面兩個(gè)索引為空的捷徑也可以使用。操作如下:
>>> number[::3]
[1, 4, 7, 10]
上面的操作將序列中每3個(gè)元素的第一個(gè)提取出來(lái),前面兩個(gè)索引都設(shè)置為空。步長(zhǎng)設(shè)置為0是否可行呢?輸入如下:
>>> number[::0]
Traceback (most recent call last):
File "<pyshell#73>", line 1, in <module>
number[::0]
ValueError: slice step cannot be zero
輸出結(jié)果告訴我們步長(zhǎng)不能為0。
步長(zhǎng)是否可以為負(fù)數(shù)呢?輸入如下:
>>> number[10:0:-2]
[10, 8, 6, 4, 2]
>>> number[0:10:-2]
[]
>>> number[::-2]
[10, 8, 6, 4, 2]
>>> number[5::-2]
[6, 4, 2]
>>> number[:5:-2]
[10, 8]
>>> number[::-1]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> number[10:0:-1] #第二個(gè)索引為0,取不到序列中的第一個(gè)元素
[10, 9, 8, 7, 6, 5, 4, 3, 2]
>>> number[10::-1] #設(shè)置第二個(gè)索引為空,可以取到序列的一個(gè)元素
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> number[2::-1] #設(shè)置第二個(gè)索引為空,可以取到序列的一個(gè)元素
[3, 2, 1]
>>> number[2:0:-1] #第二個(gè)索引為0
上面的輸出結(jié)果好像不太好理解,使用負(fù)數(shù)步長(zhǎng)時(shí)的結(jié)果怎么跟使用正數(shù)步長(zhǎng)的結(jié)果相反呢?這就是正數(shù)步長(zhǎng)和負(fù)數(shù)步長(zhǎng)的不同。
對(duì)于正數(shù)步長(zhǎng),Python會(huì)從序列的頭部開(kāi)始向右提取元素,直到最后一個(gè)元素;對(duì)于負(fù)數(shù)步長(zhǎng),則是從序列的尾部開(kāi)始向左提取元素,直到第一個(gè)元素。正數(shù)步長(zhǎng)必須讓開(kāi)始點(diǎn)小于結(jié)束點(diǎn),而負(fù)數(shù)步長(zhǎng)必須讓開(kāi)始點(diǎn)大于結(jié)束點(diǎn)。
注意:通過(guò)示例可以看到,使用負(fù)數(shù)步長(zhǎng)時(shí),設(shè)置第二個(gè)索引為空才能取到序列的第一個(gè)元素。
3.序列相加
使用加號(hào)可以進(jìn)行序列的連接操作,輸入如下:
>>> [1,2,3]+[4,5,6]
[1, 2, 3, 4, 5, 6]
>>> a=[1,2]
>>> b=[5,6]
>>> a+b
[1, 2, 5, 6]
>>> s='hello,'
>>> w='world'
>>> s+w
'hello,world'
由上面的輸出結(jié)果可以看到,數(shù)字序列可以和數(shù)字序列通過(guò)加號(hào)連接,連接后的結(jié)果還是數(shù)字序列;字符串序列也可以通過(guò)加號(hào)連接,連接后的結(jié)果還是字符串序列。數(shù)字序列是否可以和字符串序列相加呢?結(jié)果是數(shù)字序列還是字符串序列呢?輸入如下:
>>> [1,2]+'hello'
Traceback (most recent call last):
File "<pyshell#103>", line 1, in <module>
[1,2]+'hello'
TypeError: can only concatenate list (not "str") to list
>>> type([1,2]) #取得[1,2]的類(lèi)型為list
<class 'list'>
>>> type('hello') #取得hello 的類(lèi)型為字符串
<class 'str'>
由上面的輸出結(jié)果可以看到,數(shù)字序列和字符串序列不能通過(guò)加號(hào)連接。錯(cuò)誤提示的信息是:只能列表和列表相連。
由試驗(yàn)結(jié)果可以得知:只有類(lèi)型相同的序列才能通過(guò)加號(hào)進(jìn)行序列連接操作,不同類(lèi)型的序列不能通過(guò)加號(hào)進(jìn)行序列連接操作。
4.乘法
注意此處的乘法并不是數(shù)學(xué)中定義的乘法。
用一個(gè)數(shù)字x乘以一個(gè)序列會(huì)生成新的序列。在新的序列中,原來(lái)的序列將被重復(fù)x次,這就是序列中的乘法。在交互模式下輸入:
>>> 'hello'*5
'hellohellohellohellohello'
>>> [7]*10
[7, 7, 7, 7, 7, 7, 7, 7, 7, 7]
從輸出結(jié)果看到,序列被重復(fù)了對(duì)應(yīng)的次數(shù),而不是做了數(shù)學(xué)中的乘法運(yùn)算。
在Python中,序列的乘法有什么特殊之處呢?
如果要?jiǎng)?chuàng)建一個(gè)重復(fù)序列,就可以像上面的示例一樣乘以一個(gè)想要得到的序列長(zhǎng)度的數(shù)字,這樣可以快速得到需要的列表,非常方便。
空列表可以簡(jiǎn)單通過(guò)兩個(gè)中括號(hào)([])表示,表示里面什么東西都沒(méi)有。如果想創(chuàng)建一個(gè)占用10個(gè)或更多元素的空間,卻不包括任何有用內(nèi)容的列表,該怎么辦呢?我們可以像上面的示例一樣乘以10或?qū)?yīng)的數(shù)字,得到需要的空列表,也很方便。
如果要初始化一個(gè)長(zhǎng)度為x的序列,就需要讓每個(gè)編碼位置上都是空值,此時(shí)需要一個(gè)值代表空值,即里面沒(méi)有任何元素,可以使用None。None是Python的內(nèi)建值,確切含義是“這里什么也沒(méi)有”。例如,輸入如下:
>>> sq=[None]*5 #初始化sq 為含有5 個(gè)None 的序列
>>> sq
[None, None, None, None, None]
從示例我們可以看到,Python中的序列乘法可以幫助我們快速做一些初始化操作。序列乘法做一些重復(fù)操作、空列表和None初始化操作還是挺方便的。
5.成員資格
為了檢查一個(gè)值是否在序列中,Python為我們提供了in運(yùn)算符。in運(yùn)算符和前面討論過(guò)的運(yùn)算符有些不同。in運(yùn)算符用于檢驗(yàn)?zāi)硞€(gè)條件是否為真,并返回檢驗(yàn)結(jié)果,檢驗(yàn)結(jié)果為真返回True,結(jié)果為假返回False。這種運(yùn)算符稱(chēng)作布爾運(yùn)算符,返回的真值叫作布爾值。關(guān)于布爾運(yùn)算符的更多內(nèi)容會(huì)在后續(xù)章節(jié)中進(jìn)行介紹。
下面我們嘗試使用in在交互模式輸入:
>>> greeting='hello,world'
>>> 'w' in greeting #檢測(cè)w 是否在字符串中
True
>>> 'a' in greeting
False
>>> users=['xiaomeng','xiaozhi','xiaoxiao']
>>> 'xiaomeng' in users #檢測(cè)字符串是否在字符串列表中
True
>>> 'xiaohuai' in users
False
>>> numbers=[1,2,3,4,5]
>>> 1 in numbers #檢測(cè)數(shù)字是否在數(shù)字列表中
True
>>> 6 in numbers
False
>>> eng='** Study python is so happy!**'
>>> '**' in eng #檢測(cè)一些特殊字符是否在字符串中
True
>>> '$' in eng
False
>>> 'a' in numbers
False
>>> 3 in greeting
Traceback (most recent call last):
File "<pyshell#123>", line 1, in <module>
3 in greeting
TypeError: 'in <string>' requires str
由上面的輸出結(jié)果可以看到,使用in可以很好地檢測(cè)字符或數(shù)字是否在對(duì)應(yīng)的列表中。并且可以看出,數(shù)字類(lèi)型不能在字符串類(lèi)型中通過(guò)in進(jìn)行成員資格檢測(cè),而字符串類(lèi)型可以在數(shù)字列表中通過(guò)in進(jìn)行成員資格檢測(cè)。
6.長(zhǎng)度、最小值和最大值
Python為我們提供了長(zhǎng)度、最大值和最小值的內(nèi)建函數(shù),對(duì)應(yīng)的內(nèi)建函數(shù)分別為len、max和min。
這3個(gè)函數(shù)該怎么使用呢?在交互模式輸入:
>>> numbers=[300,200,100,800,500]
>>> len(numbers)
5
>>> max(numbers)
800
>>> min(numbers)
100
>>> max(5,3,10,7)
10
>>> min(7,0,3,-1)
-1
由上面的結(jié)果可以看到,len函數(shù)返回序列中所包含元素的數(shù)量,max函數(shù)和min函數(shù)分別返回序列中最大和最小的元素。在該示例中,前面幾個(gè)函數(shù)的輸入?yún)?shù)都是序列,可以使用前面的解釋理解。max和min函數(shù)的參數(shù)不是一個(gè)序列,而是以多個(gè)數(shù)字直接作為參數(shù),此處直接求取多個(gè)數(shù)字的最大值和最小值。