1. 程式人生 > >Python自學指南---基礎篇(六)資料型別-序列

Python自學指南---基礎篇(六)資料型別-序列

在上一章中提到,Python中提到的“序列”,通常指的是三種資料型別:string(字串)、list(列表)、tuple(元組)。在本章依舊先對每種型別做一個基本的瞭解,再介紹一些操作符和函式。本章所介紹的是針對三種類型的一些共性操作,各個型別的獨特特性將再之後的章節中涉及。

6.1 序列物件

Python中序列物件的特點是由一組有序的元素排列而成,並且可以通過起始為0的下標偏移量訪問到任意一個元素

>>> str1 = 'abc'
>>> str1[1]
'b'
>>> list1 = [9, 'a', 0.2]
>>> list1[
3] ##陣列訪問越界 Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range

6.1.1 字串

Python3.x中,字串型別有兩種:str和bytes,定義字串的時候採用無字首或字首u代表str型別,採用字首b代表bytes型別

#Python 3.6.5 
>>> s1 = "abc"
>>> s2 = u"abc"
>>>
s3 = b"abc" >>> type(s1) <class 'str'> >>> type(s2) <class 'str'> >>> type(s3) <class 'bytes'>

Python3中,str型別以字元為單位進行處理,儲存的是Unicode編碼的字元或字串,每個字元用字元本身或者字元的Unicode編碼來表示都可以但列印時都是列印字元本身。

>>> s1 = '中文'
>>> s2 = '\u4e2d\u6587'      #‘中文'的unicode編碼
>>> s1 == s2 True >>> s2 '中文'

bytes字串以位元組為單位進行處理,組成形式必須是十六進位制數,或者ASCII字元。bytes字串實際上儲存的是具體字元的二進位制編碼,至於編碼表示怎樣的字元,則是由具體的編碼格式而定。

利用encode()和decode()函式,可以實現str和bytes的轉換

>>> s1 = '中文'
>>> b1 = s1.encode('utf-8')   #b1是bytes形式, 儲存的是'中文'的utf-8編碼
>>> b1    
b'\xe4\xb8\xad\xe6\x96\x87'
>>> b1.decode('utf-8')    #用utf-8對b1解碼
'中文'

字串可以利用下標訪問到任何一個字元,但是字串中的任意一個字元都不能修改,因此字串是一種不可變物件。

>>> s = '123'
>>> s[0]
'1'
>>> s[0] = 9                #修改字元會報錯
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

方便起見,在之後詳細演示字串時都會利用無字首的字串,相應的操作都可以運用到有字首的字串中。

6.1.2 列表(list)

字串是一種儲存一段字元或位元組的序列,列表則是一個可以儲存任意物件的序列,利用[]或工廠方法list建立

>>> l1 = ['abc', 123, 4.98, ['j', 'k']]
>>> l1
['abc', 123, 4.98, ['j', 'k']]
>>> l2 = list('123456')
>>> l2
['1', '2', '3', '4', '5', '6']

與字串不同的是,list是一種可變物件,在建立之後仍然可以修改、新增、刪除其中的元素。
修改:可以直接利用下標

>>> l1 = ['abc', 123, 4.98, ['j', 'k']]
>>> l1[1] = 'ok'
>>> l1
['abc', 'ok', 4.98, ['j', 'k']]

新增,用insert(index, obj)函式在指定位置新增,或者利用append()函式在末尾新增

>>> l1 = [1, 'a', 'abc']
>>> l1.insert(2, 3)    #在下標2的位置插入3
>>> l1
[1, 'a', 3, 'abc']          
>>> l1.append('last')     #末尾加入'last'
>>> l1
[1, 'a', 3, 'abc', 'last']

刪除,用pop(i)在指定位置刪除元素

>>> l1 = [1, 'a', 'abc']
>>> l1.pop(2)    #在下標2的位置插入3
>>> l1
[1, 'a']

或者利用remove(obj)刪除指定元素,使用這個方法必須事先確定序列中有該元素,否則會丟擲異常

>>> l1 = [1, 'a', 'abc']
>>> l1.remove(1)
>>> l1
['a', 'abc']
>>> l1.remove(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list

6.1.3 元組(tuple)

tuple與list非常類似,區別在於tuple是不可變物件,因此內部的元素不能修改、新增或刪除。元組利用()或工廠方法tuple來建立

>>> t1 = (1, 'a', 'abc')
>>> t1
(1, 'a', 'abc')
>>> t2 = tuple('123')
>>> t2
('1', '2', '3')

6.2 針對序列物件的操作符

6.2.1、連線操作符(+)

利用+可以將多個相同型別的序列做連線:

>>> s1 = "123"
>>> s2 = "456"
>>> s1 + s2
'123456'
>>> l1 = ['5', 7, 'abc']
>>> l2 = ['12345', 'opq']
>>> l3 = ['1', 2]
>>> l1 + l2 + l3
['5', 7, 'abc', '12345', 'opq', '1', 2]

每一次連線運算+實際上都會生成一個新的物件,多個序列連加的過程中也就會產生許多的新物件,因此對於多個字串連線的操作,可以利用join()方法來代替:

>>> l1 = ['a', 'b', 'cd', 'efg']  #可以把需要連線
>>> ''.join(l1)
'abcdefg'
>>> '-'.join(l1)
'a-b-cd-efg'

對於列表(list)而言,可以使用extend()方法完成連線,並且不會建立新的物件

>>> l1 = [1, 'a', 3]          
>>> l1.extend([4, 'b'])     
>>> l1
[1, 'a', 3, 4, 'b']

注意不要與append()方法混淆,使用append()會將傳入的任何物件都當作最後一個元素加入到列表中:

>>> l1 = [1, 'a', 3]          
>>> l1.append([4, 'b'])     
>>> l1
[1, 'a', 3, [4, 'b']]
6.2.2、重複操作符

重複操作符*可以返回一個包含多個原序列物件拷貝的新物件

>>> "abc" * 3
'abcabcabc'
6.2.3、切片([],[:], [::])

利用下標[index]可以訪問序列中的任意一個元素,這種簡單的用方括號加一個下標的方式也是一種切片操作。更進一步,如果想“切”序列中的某一部分,可以利用[:][::]來實現。

[starting_index:ending_index] 可以用於訪問起始索引到結束索引的元素,注意不會包括結束索引的元素

>>> l = [1, 2, 3, 4]
>>> l[1:3]
[2, 3]  #不會包括索引位置為3的元素4

起始索引和結束索引可以省略,分別表示從起始位置索引和索引到末尾

>>> l = [1, 2, 3, 4]
>>> l[:3]
[1, 2, 3]  
>>> l[1:]
[2, 3, 4] 
>>> l[:]
>>>[1, 2, 3, 4] 

還可以採用負向索引,例如[-1]就代表取倒數第一個元素,[-3]代表倒數第三個

>>> l = [1, 2, 3, 4]
>>> l[-3:3]
[2, 3]
>>> l[-4:-2]
[1, 2]  
>>> l[-4:]
[1, 2, 3, 4] 

注意無論使用正向還是反向索引,切片取元素的方向都是正向的。換言之,如果ending_index<=starting_index,肯定是取不到任何元素的。

>>> l = [1, 2, 3, 4]
>>> l[3:2]
[]
>>> l[-2:-4]
[]   

還可以利用[starting_index:ending_index:step] 的形式,每隔一定步長step 取一個元素,例如:

>>> l = [1, 2, 3, 4, 5, 6]
>>>> l[1:4:2]
[2, 4]
>>> l[::2]
[1, 3, 5]
>>> l[::3]
[1, 4]

step 設為負數,就可以實現反向取元素:

>>> l = [1, 2, 3, 4, 5, 6]
>>> l[::-2]
[6, 4, 2]

6.3 一些內建函式

6.3.1 型別轉換

str(),list(),tuple(),可以分別將傳入的物件轉換為字串,列表,元組。

str()可以傳入任意的obj物件,並且輸出物件的字串形式,例如:

>>> l = [1, 2, 3, 4, 5, 6]
>>> str(l)
'[1, 2, 3, 4, 5, 6]'

list(),tuple()可以傳入任意的可迭代物件,可迭代物件除了容器物件外,還包括檔案物件、管道物件等等。輸出的形式一般就是將可迭代物件中包含的每一個物件拆分,分別放入list或tuple。

>>> s = "123"
>>> list(s)
['1', '2', '3']
>>> l = [1, 2, 3, 4, 5, 6]
>>> tuple(l)
(1, 2, 3, 4, 5, 6)
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> list(d)
['Bob', 'Michael', 'Tracy']   #對於dict物件,實際上是對d.keys()的淺拷貝
6.3.2 可操作內建函式

以下介紹幾個可操作內建函式

1、len(seq)

返回seq序列的長度
2、reversed(seq)

返回一個反轉序列的迭代器

注:list物件有一個reverse方法,可以反轉原list:

>>> l = [1,2,3]
>>> id(l)
4353355720
>>> l.reverse()
>>> id(l)
4353355720
>>> l
[3, 2, 1]

3、sum(iterable, start=0)

返回可迭代物件iterable內元素的和,start指定初始相加的引數,預設值為0。

>>> l = [3, 2, 1]
>>> sum(l)    #執行的是0+3+2+1
6 
>>> l2 = ['1', '2']
>>> sum(l2)  #會報錯,因為0不能與直接字元相加
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'   
>>> sum(a,'0')   #即使將初始值設為字元,也會報錯
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sum() can't sum strings [use ''.join(seq) instead]  

4、reduce(function, iterable, initializer = 0)

reduce() 方法會對可迭代物件iterable中元素進行累積。function是具體累積操作的函式,initializer指定初始引數,預設為0

可以利用reduce()方法實現之前的sum()方法:

>>>from functools import reduce  #python3之後,需要從fucntools模組中匯入
>>>def add(x, y) :            # 兩數相加
...     return x + y
... 
>>> reduce(add, [1,2,3,4,5])   # 計算列表和:1+2+3+4+5
15
>>> reduce(lambda x, y: x+y, [1,2,3,4,5])  # 使用 lambda 匿名函式
15
>>> import operator
>>> reduce(operator.add, [1,2,3,4,5])  # 使用operator模組中的方法代替lambda函式也是常用的一種操作
15

5、zip(iterable)

zip()方法將可迭代的物件iterable作為引數,將物件中對應的元素打包成一個個元組,然後返回由這些元組組成的列表**(python3返回迭代器)**。

>>> a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b)     # 返回一個物件
>>> zipped
<zip object at 0x103abc288>  #返回迭代器
>>> list(zipped)  # list() 轉換為列表
[(1, 4), (2, 5), (3, 6)]
>>> list(zip(a,c))              # 元素個數與最短的列表一致
[(1, 4), (2, 5), (3, 6)]
 
>>> a1, a2 = zip(*zip(a,b))          # 與 zip 相反,zip(*) 可理解為解壓,返回二維矩陣式
>>> list(a1)
[1, 2, 3]
>>> list(a2)
[4, 5, 6]
>>>

6、enumerate(iterable, start=0)

該方法用於將一個可迭代物件組合為一個索引序列,同時列出資料和資料下標,返回的是一個enumerate物件,同時也是這個索引序列對應的迭代器一般用在 for 迴圈當中,可以同時獲取元素和對應下標

>>>seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]

>>>seq = ['one', 'two', 'three']
>>> for i, element in enumerate(seq):   #利用for獲取迭代器內元素
...     print i, element
... 
0 one
1 two
2 three

7、sorted(iterable, cmp = None, key = None, reverse = False)

sorted()方法可以對可迭代物件iterable進行排序,並返回排序後的新物件,排序規則可以利用func和key兩個引數指定,預設都為None,reverse預設為False,一般代表升序排列

最簡單的用法,返回一個列表的升序排列:

>>> l = [1, 3, 9, 0]
>>> sorted(l)
[0, 1, 3, 9]

cmp是一個比較的函式,該函式具有兩個引數,引數的值都是從可迭代物件中取出,此函式必須遵守的規則為,大於則返回1,小於則返回-1,等於則返回0。也就是說如果cmp = func(x, y),x,y此時代表可迭代物件中的任意兩個元素,那麼:

  • 如果func返回-1,那麼x排在y前面
  • 如果func返回0,那麼x,y相對位置不變
  • 如果func返回1,那麼x排在y後面

舉例而言:

>>> L=[('b',2),('a',1),('c',3),<