導語:本文章記錄了本人在學習Python基礎之數據結構篇的重點知識及我的心得,以加深本身的理解。
本文重點:html
一、瞭解列表、元組、字節序列、數組等數據結構;
二、瞭解上述數據結構相對應的迭代、切片、排序、拼接操做;
三、若是想把代碼寫的Pythonic,在保證代碼可讀性的前提下,代碼行數越少越好。
容器序列可以存放不一樣類型的數據,比扁平序列更靈活;
扁平序列只能存放一種類型的原子性的數據,體積更小速度更快。eg:數字,字符字節python
一、列表推導:在[]中使用命令語句加for甚至if實現迭代推導出新列表的操做。
列表推導運用得當將使得代碼清晰優雅。
Python3中不存在Python2的列表推導變量泄漏問題,即列表推導中的局部變量與主程序的同名變量引用衝突問題。算法
eg1:利用ord()把單詞apple的ASCII碼以列表存起來。express
list_a=[ord(x)for x in "apple"]#ord()是返回字符對應ASCII碼的函數。 print(list_a)#輸出:[97, 112, 112, 108, 101]
eg2:使用列表嵌套循環求笛卡爾積。數組
Clothes=["T-shirt","sweater"] Color=["red","yellow","blue"] Product=[(x,y)for x in Clothes for y in Color]#嵌套循環 print(Product)#輸出:[('T-shirt', 'red'), ('T-shirt', 'yellow'), ('T-shirt', 'blue'), ('sweater', 'red'), ('sweater', 'yellow'), ('sweater', 'blue')]
句法提示
:Python會忽略[ ],{ },( )中的換行符" ",把括號內的多行內容視爲一行。所以可在列表、列表推導、字典、生成器表達式中省略換行符。安全
二、學習生成器表達式應先了解的概念:
迭代器協議:對象必須提供next方法,執行該方法會返回迭代中的下一項,直到引發stopiteration中止迭代。
可迭代對象:實現迭代器協議的對象(實現方法:對象內部定義__iter__方法)任何可迭代對象均可以使用for循環。由此看出Python的for循環抽象程度高於Java。
數據結構
使用Iterable判斷一個對象是否可迭代:
app
from collections import Iterable print(isinstance("apple", Iterable))#True可迭代 print(isinstance(100, Iterable))#False不可迭代
三、生成器表達式:按需返回一個結果對象,而非先構建一個完整的列表。
表達方法:語句格式與列表推導相似,但須在圓括號()中書寫。
特色:按需產值,延遲計算,節省內存,在生成大規模序列類型具有優點。
dom
eg1:用生成器表達式初始化元組函數
tuple_a=(ord(x)for x in "apple") for i in tuple_a: print(i)
eg2:用生成器表達式初始化數列
from array import array ascii=array('I',(ord(x)for x in "apple")) for i in ascii: print(i)
eg3:用生成器表達式計算笛卡爾積
Clothes=["T-shirt","sweater"] Color=["red","yellow","blue"] tuple_Product=((x,y)for x in Clothes for y in Color) for i in tuple_Product:#生成器表達式是按需產值,沒法用print直接一次性輸出,須要配合for迭代輸出 print(i)
元組有兩重功能,一是看成記錄來用的數據模型,二是充當不可變的列表,
元組用做記錄時,能夠理解爲數據+位置。之因此提位置是由於有序的位置賦予了數據獨特的意義。若是此時對元組進行排序等打亂位置的操做,會使得元組丟失本來所攜帶的信息。
Traveler_ids=[("hoya","85236669"),("Dennis","O7856P77"),("Sky","L336636")] for i in Traveler_ids: print("%s/%s"%i)#平行賦值,元組拆包 #輸出: hoya/85236669 Dennis/O7856P77 Sky/L336636
for name,_ in Traveler_ids:#對於拆包中不感興趣的一類元素能夠用佔位符「_" print(name) #輸出: hoya Dennis Sky
元組拆包能夠應用到任何可迭代對象上,惟一的硬性要求是,被可迭代對象中的元素數量必須與接受這些元素的元組的空擋數一致。
t=(9,4) print(divmod(*t))#利用*能夠把一個可迭代對象拆開做爲函數的參數,輸出爲(2, 1) a=3 b=5 a,b=b,a#不使用中間變量實現值的交換 print(a,b)
用*來處理剩下的元素:星號*能夠把不肯定參數裝到一塊兒。注意在平行賦值中,星號*只能用在一個變量名前面,可是這個變量能夠出如今賦值表達式的任意位置。
a,b,*rest=range(5) print(a,b,rest)#輸出爲:0 1 [2, 3, 4] a,*rest,b=range(5) print(a,rest,b)#輸出爲0 [1, 2, 3] 4
format函數輸出通常格式:.
通常格式[fill,align,sign,0,width,.precision,type],每一處都是可選的.
format函數字符串映射方式:
print("{1}|{2}|{1}".format("a","b","c"))#經過位置填充。輸出:b|c|b print("{}|{}|{}".format("a","b","c"))#也能夠不填寫位置索引,默認按照順序填充。輸出:a|b|c
print("{Greeting},My name is {name}".format(Greeting="Hello",name="Hoya")) #輸出:Hello,My name is Hoya Fruit_number={"apple":15,"pear":10,"strawberry":20} print("We have {x[apple]} apples,{x[pear]} pears,and {x[strawberry]} strawberries.".format(x=Fruit_number))#字典的key也能填充字符串。注意x是局部變量! #輸出:We have 15 apples,10 pears,and 20 strawberries.
Friends=["Daniel","Dennis"] print("I have two best friends,one is {x[0]},the other is {x[1]}".format(x=Friends)) #輸出:I have two best friends,one is Daniel,the other is Dennis
本質上是位置索引,由於傳入的對象非具體元素而是列表,故用下標填充。
class Students: def __init__(self,x,y): self.x=x self.y=y def __str__(self): return "Hello,My name is {self.x},I come from {self.y}".format(self=self) print(Students("Hoya","China"))#傳入類,把類的屬性值填充到字符串中format&嵌套元組實例綜合運用: cities=[("New York","USA",(40.8086,-74.0204)), ("Mexico City","Mexico",(19.4333,-99.1333)), ("Tokyo","Japan",(35.6899,169.3254)), ("Sao Paul","USA",(-23.5478,-46.6358))] print("{:15}|{:^9}|{:^9}".format("","lat","long")) x="{:15}|{:^9.2f}|{:^9.2f}"#對經緯度小數點後保留兩位數字 for city,_,(lat,long) in cities :#平行賦值,對應結構一致。 if long < 0: print(x.format(city,lat,long))#輸出以下: | lat | long New York | 40.80 |-74.02 Mexico City | 19.43 |-99.13 Sao Paul |-23.54 |-46.63
namedtuple:具名元組,來自標準庫中的collections模塊中的方法。它能夠構建一個帶字段名的元組和一個有名字的類。
特色:可以直接使用名字訪問元素。
注意:
與tuple相同,namedtuple屬性不可變!
namedtuple屬性與方法:
應用實例:
from collections import namedtuple Star=namedtuple("Star", "name country coordinates age") hoya=Star("Hoya","China",(20,30),18) print(hoya.name)#讀取信息的兩種方式 print(hoya[0]) print(Star._fields) Jack_data=("Jack","Russia",(100,36),14) # Jack=Star(*Jack_data)#此方法與_make(iterable)類方法效果相同 Jack=Star._make(Jack_data) print(Jack.age) print(Jack._asdict()) for key,value in Jack._asdict().items():#字典內置方法items()而非item() print(key+":",value)#加號先後字符類型一致
元組除了不支持增減,逆序,就地修改等直接或間接改變元素信息及位置的方法以外,支持列表其餘的全部方法。
因爲方法過多不便展現,詳情參考Fluent Python P27以及Python基礎教程筆記列表方法。
切片通常格式s[a:b:c],c取值爲負意味着反向取值。
注意:若是賦值對象是切片,賦值號另外一端的對象也必須是可迭代對象。即便單獨一個值,也要把它轉換成可迭代的序列。
反例:
list1=[1,3,6,9,10] list1[1:3]=2#正確形式:list1[1:3]=[2] Traceback (most recent call last): File "F:\xuexi\Fluent Python\section 2-4.py", line 3, in <module> list1[1:3]=2 TypeError: can only assign an iterable#切片右端必須是可迭代對象。
列表儘管具備靈活簡單的特色,但並不能適用於各類需求,爲此咱們要尋找更好的選擇。下面介紹三種在某些狀況下能夠替換列表的數據類型。
若是咱們須要一個只包含數字的列表,那麼array.array比list更高效。
構造數組的通常格式:array(typecode,[ initializer])
typecode指數組類型,經常使用的以下:initializer相似列表推導
Type code | C Type | Python Type | Minimum size in bytes |
---|---|---|---|
'b' | signed char | int | 1 |
'B' | unsigned char | int | 1 |
'i' | signed int | int | 2 |
'I' | unsigned int | int | 2 |
'l' | signed long | int | 4 |
'L' | unsigned long | int | 4 |
'f' | float | float | 4 |
'd' | double | float | 8 |
數組方法:數組支持全部跟可變序列有關的操做,
可參考Fluent Python P42以及array的Python官方library.數組從Python3.4開始不支持諸如list.sort()這種就地排序的方法。
另外數組提供讀寫文件更快的方法,如.frombytes和.tofile
eg:綜合運用
from random import random from array import array array1=array("d",(random()for x in range(10^5)))#構建數組 fp=open("array1.bin","wb")#以二進制形式存儲文件 array1.tofile(fp)#打開文檔導入數據 fp.close()#關閉文檔 print(array1[-1]) array2=array("d") fp=open("array1.bin","rb") array2.fromfile(fp, 10^5) fp.close() print(array2[-1]) print(array1==array2)#輸出True,說明存取無誤。
collections.deque類(雙向隊列)是一個線程安全、能夠快速從兩端添加或者刪除的數據類型。
deque構造:deque([initializer],maxlen=some_number)#傳入初值和maxlen參數。初值可在中括號中,也可採起相似列表推導的方法;maxlen限制deque的元素數量,選填。
deque方法:
注意是逆序輸入(由於是逐個迭代插入的關係)
eg:
from collections import deque deque1=deque([x*x for x in range(3)],maxlen=5) print(deque1)#deque([0, 1, 4], maxlen=5) deque1.extendleft([9,16,25])#隊列滿元素後,一端添加的元素會使得另外一端刪除同等數量的元素保持maxlen不變 print(deque1)#deque([25, 16, 9, 0, 1], maxlen=5) deque1.rotate(-3) print(deque1)#deque([0, 1, 25, 16, 9], maxlen=5) deque1.popleft() print(deque1)#deque([1, 25, 16, 9], maxlen=5)
deque實現了大部分列表所擁有的方法,具備靈活多用和線程安全
的特色;但deque從中間刪除元素的操做會慢一些。注:deque不支持切片操做(我的實踐經驗)
memoryview實際上是泛化和去數學化的NumPy數組。
它讓你在不須要複製內容的前提下在數據結構之間共享內存;數據結構能夠是任何形式。
list1=[["_"]*3 for x in range(3)]
list2=[["_"]3]3
list11=1
list21=1
print(list1)#[['_', '_', '_'], ['_', 1, '_'], ['_', '_', '_']]
print(list2)#[['_', 1, '_'], ['_', 1, '_'], ['_', 1, '_']]
上文代碼是兩種初始化嵌套列表的方式,仔細觀察發現list2的賦值後在3個子列表中均有賦值,這是錯誤的初始化方法。緣由在於list2初始化的子列表引用一致,這種列表每每不是咱們想要的結果。
教訓:a*n語句中,若是序列a的裏的元素是對其餘可變對象的引用,就須要額外小心。緣由是會產生指向同一個可變對象的屢次引用!
原子操做
:不會被線程調度機制打斷的操做,一旦執行將運行到結束。
eg:
cities=["New York","Mexico City","Tokyo","Sao Paul"] print(sorted(cities,key=len,reverse=True))#['Mexico City', 'New York', 'Sao Paul', 'Tokyo'] cities.sort(reverse=True) print(cities)#['Tokyo', 'Sao Paul', 'New York', 'Mexico City']
sorted通常格式:
sorted(iterable,[,key[,reverse=True]]])
eg:
students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 13)] print(sorted(students, key=lambda s: s[0]))#lambda是匿名函數;s(0)表明把可迭代對象中待排序元素中的第一個元素取出比較排序,這裏是諸如"john"的英文字符串。 #輸出:[('dave', 'B', 13), ('jane', 'B', 12), ('john', 'A', 15)]
bisect.bisect(haystack,needle):返回一個在haystack中插入needle保持序列升序的位置。
bisect.insort(seq,item):返回一個在seq中插入item保持序列升序的新序列。
bisect和insort同樣,能夠額外填寫lo和hi兩個參數控制
To learn more:https://docs.python.org/3/lib...
eg:
import bisect list3=[1,3,5,7,9] s=8 print(bisect.bisect(list3,s))#輸出:4 bisect.insort(list3,s) print(list3)#輸出:[1, 3, 5, 7, 8, 9]