Python序列構成的數組

 

一、內置序列類型

容器序列:list,tuple,collections.deque  (能存放不一樣類型)html

扁平序列:str,bytes,bytearray,memoryview,array.arraypython

▲ 容器序列存放的是所包含的任意類型的對象引用。算法

可變序列:list,bytearray,memoryview,array.array,collection.deque編程

不可變序列:str,tuple,bytes數組

 

二、列表推導式、生成器表達式

2.一、列表推導和生成器表達式安全

列表推導(listcomps)是構建列表的快捷方式,一般原則是隻用列表推導來建立新的列表。網絡

生成器表達式(genexps)用來建立其餘類型的序列。app

>>> x = 'ABC'
>>> dummy = [ord(x) for x in x]
>>> x
'ABC'
>>> dummy
[65,66,67]

Python3 中的列表推導式、生成器表達式、集合推導、字典推導都有本身的局部做用域。表達式內部的變量和賦值只在局部做用域生效。dom

列表推導能夠幫助咱們把一個序列或是其餘可迭代類型中的元素進行過濾或是加工,而後再新建一個列表。異步

2.二、列表推導同 filtermap 比較

>>> x = 'ABCDEF'
>>> dummy = [ord(x) for x in x if ord(x)>66]
>>> dummy
[66,67,68,69,70]
>>> dummy = list( filter(lambda c:c>66,map(ord,x)) )
>>> dummy
[66,67,68,69,70]  

2.三、生成器表達式

生成器表達式遵照迭代器協議,能夠逐個產出元素,而不是先創建一個完整的列表。

▲ 生成器表達式的語法和列表推導差很少,只是把方括號改爲圓括號!

colors  = ['black','white']
sizes = ['S','M','L']
for tshirt in ('%s %s'%(c,s) for c in colors for s in sizes):
    print(tshirt)

 

三、元組

3.一、元組的拆包

元組除了用做不可變的列表,它還能夠用於沒有字段名的記錄

元組的拆包形式之一(平行賦值)

>>> scores = (93,97)
>>> CN,EN = scores   #元組拆包
>>> CN
93
>>> EN
97

不使用中間變量交換元素

>>> a,b = b,a

用 * 運算符把 可迭代對象 拆開做爲函數的參數

>>> t = (20,8)
>>> divmod(*t)
(2,4)

讓函數用元組的形式返回多個值

>>> import os 
>>> _,filename = os.path.split('/home/abc.py')
>>> filename
abc.py

_ 佔位符能幫助處理不感興趣的數據。

用 * 號處理剩下的元素(這個變量能夠放在賦值表達式的任意位置)

>>> a,b,*rest = range(5)
>>> a,b,rest
(0,1,[2,3,4])

>>> a,*body,b,c = range(5)
>>> a,*body,b,c
(0,[1,2],3,4)

嵌套元組的拆包

class1 = [
    ('xiaoming','Boy',(85,88,90)),
    ('xiaohong','Girl',(90,88,90)),
]
for name,sex,scores in class1:
    print(name,sex,scores)

3.二、具名元組

collections.namedtuple 是一個工廠函數,用來建立一個帶字段名的元組和一個有名字的類。

建立一個具名元組須要兩個參數,一個是類名,另外一個是類的各個字段的名字。

能夠是由數個字符串組成的可迭代對象,或者是由空格分隔開的字段名組成的字符串

>>> from collections import namedtuple
>>> City = namedtuple('City','name country population coordinates')    # <class '__main__.City'>
>>> tokyo = City('Tokyo','JP',38.32,(35.68872,139.25436))
>>> tokyo
City(name='Tokyo', country='JP', population=38.32, coordinates=(35.68872, 139.25436))
>>> tokyo.population
38.32
>>> tokyo[0]
'Tokyo'

具名元組還具備本身專有屬性:_fields類屬性,類方法_make(iterable),實例方法_asdict()

>>> City._fields
('name', 'country', 'population', 'coordinates')

>>> LatLong = namedtuple('LatLong','lat long')
>>> delhi_data = ('Delhi NCR','IN',32.21,LatLong(28.45721,76.89342))
>>> delhi = City._make(delhi_data)     # 生成實例相似 City(*delhi_data)

>>> delhi._asdict()
OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 32.21), ('coordinates', LatLong(lat=28.45721, long=76.89342))])

 

四、切片

4.一、切片

在切片和區間操做裏不包含區間範圍的最後一個元素。這樣帶來的好處有:

● 當只有一個位置信息時,咱們也能夠快速看出切片和區間裏有幾個元素:range(3) 和 my_list[:3] 都返回3個元素。

● 當起止位置均可見時,能夠計算出切片和區間的長度(stop - start )

● 利用任意一個下標把序列分割成不重疊的兩部分。my_list[:x] 和 my_list[x:]

4.二、對對象進行切片

對 seq[start:stop:step] 進行求值的時候,Python會調用 seq.__getitem__(slice(start,stop,step))

>>> HTML = """ ... 文本內容 """
>>> TEXT_HEAD = slice(0,23)
>>> IMG_URL = slice(23,56)
>>> for item in HTML:
       print(item[TEXT_HEAD],item[IMG_URL])

▲ 若是賦值的對象是一個切片,那麼賦值語句的右側必須是個可迭代對象。

>>> li = list(range(10))
>>> li[2:5] = 100
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'range' object does not support item assignment
>>> li[2:5] = [100]

 

五、對序列使用 + 和 *

+ 號兩側的序列由同類型的數據所構成,在拼接的過程當中,兩個被操做的序列都不會被修改。

=》 Python會新建一個包含同類型數據的序列來做爲拼接的結果。

 

▲ 在 a * n 語句中,若是序列a裏的元素是對其餘可變對象的引用,獲得的列表裏包含的3個元素實際上是3個引用。

>>> my_list = [[]] * 3
>>> my_list
[[], [], []]
>>> print(id(my_list[0]),id(my_list[1]),id(my_list[2]))
1767860956104 1767860956104 1767860956104

>>> my_list = [[''] *3 for i in range(3) ] 
>>> print(id(my_list[0]),id(my_list[1]),id(my_list[2]))
1767860947400 1767860945992 1767860953544        

增量賦值運算符 += 和 *= 利用的特殊方法是 __iadd__ (就地加法)和 __imul__,可是若是沒有實現  __iadd__ 和 __imul__ 的話,

a += b 效果就變成了 a = a + b,首先計算 a + b,獲得一個新的對象,而後賦值給 a。

可變序列通常都實現了 __iadd__ 和 __imul__ 

一個罕見的邊界狀況:

>>> t = (1,2,[3,4])
>>> t[2] += [5,6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [3, 4, 5, 6])

▲ 不要把可變對象放在元組裏面。

▲ 增量賦值不是一個原子操做。

▲ Python 運行原理可視化分析工具 →  http://www.pythontutor.com/visualize.html#mode=edit

 

六、排序

6.一、list.sort 方法和內置函數 sorted()

list.sort 方法會就地排序列表,返回None值。

sorted() 方法會新建一個列表做爲返回值。

list.sort 和 sorted函數,都有兩個可選的關鍵字參數。

reverse :被設定爲 True,被排序的列表的元素會以降序輸出。

key:一個只有一個參數的函數,這個函數會被用在序列裏的每個元素上,所產生的結果將是排序算法依賴的對比關鍵字,如key=len

key參數也能夠對一個混有數字字符和數值的列表進行排序。

>>> l = [1,7,3,'2','6',8]
>>> sorted(l,key=int)
>>> sorted(l,key=str)

6.二、用bisect來管理已排序的序列

bisect包含兩個主要函數,bisect insort,都利用二分查找算法在有序序列中查找或插入元素。

bisect 的表現能夠從兩個方面進行:

  1. bisect 有兩個可選參數:lo 和 hi 來縮小搜尋範圍,lo默認值是0,hi默認值是序列的長度len()。
  2. bisect函數實際上是bisect_right函數的別名,還有一個bisect_left函數,區別在於新元素會放置於它相等的元素的前面
def grade(score,breakpoint=[60,70,80,90],grade='FDCBA'):
    i = bisect.bisect(breakpoint,score)
    return grade[i]

 

七、數組、內存、隊列

7.一、當列表不是首選時

若是咱們須要一個只包含數字的列表,那麼array.array 比 list 更加高效。

建立數組須要一個類型碼,類型碼用來表示在底層的C語言應該存放怎樣的數據類型。

類型代碼 C類型 Python類型 最小大小(以字節爲單位)
'b' signed char INT 1
'B' unsigned char INT 1
'u' Py_UNICODE Unicode字符 2
'h' signed short INT 2
'H' unsigned short INT 2
'i' 簽名int INT 2
'I' 無符號整數 INT 2
'l' signed long INT 4
'L' 無符號長整數 INT 4
'q' signed long long INT 8
'q' 無符號long long INT 8
'f' float float 4
'd' double float 8

數組還提供從文件讀取和存入文件的更快的方法。

from array import array
from random import random
floats = array('d',(random() for i in range(10**7)))
print(floats[-1])

fp = open('floats.bin','wb')
floats.tofile(fp)
fp.close()

floats2 = array('d')
fp = open('floats.bin','rb')
floats2.fromfile(fp,10**7)
fp.close()

▲ 數組的排序:a = array.array(a.typecode, sorted(a))

7.二、內存=視圖

memoryview 是一個內置類,能在不復制內容的狀況下操做同一個數組的不一樣切片。

a = bytearray('aaaaaaa',encoding='utf8')
 
b = a[:2]
b[:2] = b'bb'
print(a,b)      # bytearray(b'aaaaaaa')   bytearray(b'bb')
 
ma = memoryview(a)
mb = ma[:2]
mb[:2] = b'bb'
 
print(ma.tobytes(),mb.tobytes())   # b'bbaaaaa'     b'bb'

使用場景是網絡程序中socket接收和接收數據的解析

7.三、雙向隊列和其餘形式的隊列

collections.deque 類是一個線程安全,能夠快速從兩端添加或者刪除元素的數據類型。

>>> from collections import deque
>>> dq = deque(range(10),maxlen=10)
>>> dq
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.rotate(3)     # 當n>0時,最右邊n個元素移到最左邊,當n<0時,最左邊移到最右邊
>>> dq
deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
>>> dq.rotate(-4)
>>> dq
deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
>>> dq.appendleft(-1)   # 對已滿的隊列添加元素時,尾部元素會被刪除
>>> dq
deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.extend([11,22,33])
>>> dq
deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
>>> dq.extendleft([10,20,30,40])
>>> dq
deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)

其餘形式的隊列:

queue:不一樣的線程能夠利用這些數據類型交換信息。

multiprocessing:實現了本身的Queue,設計給進程間通訊用的。

asyncio:爲異步編程裏的任務提供。 

heapq:把可變序列當作堆隊列或者優先隊列使用。

相關文章
相關標籤/搜索