流畅的python目录_流畅的python python 序列
內置序列
容器類型
list 、tuple和collections.deque這些序列能放入不同的類型的數據
扁平序列
str、byets、bytearray、memoryview(內存視圖)和array.array(數組)
可變序列
list、bytearray、array.array、collections.deque和memoryview
不可變序列
tuple、str和bytes
可變序列所擁有的方法是在不可變序列的基礎上增加的.
列表推導式
簡單使用
列表是我們常見的可變序列,他是容器類型的這里主要介紹列表推導式
列表推導式是構建列表的快捷方式
例子:
將一個字符串轉換成Unicode碼位的列表
symbols='abcde'code=[]for item insymbols:
code.append(ord(item))print(code)#[97, 98, 99, 100, 101]
再來看列表推導式:
symbols='abcde'code=[ord(item) for item insymbols]print(code)
列表推導式能讓你的程序變的更加簡潔
列表推導式只用來創建新的列表,并且盡量保持簡短
列表推導式可以幫助我們把一個序列或者其他可迭代的對象中的元素過濾或者是加工,然后再創建一個新的列表
列表推導式的過濾
借助剛剛的例子,我想得到一個Unicode碼位大于99的,那么我們用內置函數map和filter來構造看看:
symbols='abcde'filter_symbols=list(filter(lambda x:x>99,map(ord,symbols)))print(filter_symbols)#[100, 101]
那么列表推導式呢?
symbols='abcde'filter_symbols=[ord(item) for item in symbols if ord(item)>99]print(filter_symbols)#[100, 101]
從上面的例子可以看出來,列表推導式更加具有可讀性
注意列表推導式變量泄露問題
在python2.x中for的關鍵字可能會影響到其他同名的變量
例子:
x='變量泄露'result=[x for x in 'ABC']print(x)#'C'
x原本的值被取代了,這不是我們想要看到的,那么這就叫變量泄露
在python3中是不會出現的.
x='變量泄露'result=[x for x in 'ABC']print(x)#變量泄露
列表推導式/生成器表達式/以及集合和字典的推導在python3中都有了自己的局部作用域.所以表達式的上下文中的變量還可以變正常的使用
元組
元組和記錄
元組其實是對數據的記錄,如果緊緊理解元組是不可變的列表,那么我們可能忽略了他的位置信息的重要性,
如果把元組當做一些字段的集合,那么數量和位置就顯的異常重要
name,age=('ming',12)
year,month,day= (2018,8,16)
tup=('ming','大帥比')print('%s:%s'%tup)
那么上面的例子就可以看出位置信息的重要性,那么列表也可以實現上面的拆包機制,但是為什么不用列表?
因為元組的是不可變序列的,如果你用列表來進行位置的拆包,如果你的列表insert了一個值,那么你的信息將會全部亂套.
元組的拆包
在上面將元組的元素分別賦值給變量,name,age同樣用一個%運算符就把tup的元素對應到了格式字符串的空檔中,這些都是對元組拆包的應用
元組的拆包可以應用到任何可迭代的對象上,但是被可迭代對象的元素數量必須跟接收這些元素的空檔數一致,除非我們用*
不用中間變量交換兩個變量的值
a,b=b,a
用*運算符把一個可迭代對象拆開作為函數的參數:
t=(20,8)
q,r=divmod(*t)print(q,r)#2,4
用*在處理剩下的元素
a,b,*rest=range(5)print(a,b,rest)#0 1 [2, 3, 4]
a,b,*rest=range(3)print(a,b,rest)#0 1 [2]
a,b,*rest=range(2)print(a,b,rest)#0 1 []
*可以出現在賦值表達式的任意位置
a,*rest,b=range(5)print(a,rest,b)#0 [1, 2, 3] 4
*rest,a,b=range(5)print(rest,a,b)#[0, 1, 2] 3 4
切片
在python中,像列表/元組/字符串這類數列支持切片操作
為什么切片和區間會忽略最后一個元素
當只有最后一個位置信息時,我們可以快速看出切片和區間的元素
range(3), my_list=[:3]
當起始和終止位置可見時,可以快速計算出切片和區間的長度,用最后一個下標減去第一個下標
分割成不重復的兩部分
my_list[:x] my_list[x:] 那么這兩個切片是不存在重復的元素
切片的賦值:
l=list(range(10))
l[2:5]=[20,30]print(l)#[0, 1, 20, 30, 5, 6, 7, 8, 9]
del l[5:7]print(l)#[0, 1, 20, 30, 5, 8, 9]
l[3::2]=[11,22]print(l)#[0, 1, 20, 11, 5, 22, 9]
#l[2:4]=100'#報錯 切片的賦值必須是可迭代的對象#print(l)
l[2:4] ='abcde' #賦值范圍超過切片范圍,同樣的會把賦值的內容全部放入列表中#[0, 1, 'a', 'b', 'c', 'd', 'e', 5, 22, 9] 且不會擠出列表原有的元素
對序列使用+和*/增量賦值
對序列使用+和*
+和*都遵循不修改原有的操作對象,而是構建一個新的序列
board=[['_']*3 for i in range(3)]
board[1][2]='x'
print(board)#[['_', '_', '_'], ['_', '_', 'x'], ['_', '_', '_']]#列表推導式,每次執行的時候都會新創建一個['_']
weird_board=[['_']*3]*3weird_board[1][2]='x'
print(weird_board)#[['_', '_', 'x'], ['_', '_', 'x'], ['_', '_', 'x']]#如果直接在本身列表里*嵌套的列表,那么里面嵌套的列表都是指同一個對象#那么可能結果不是你想要的
序列的增量賦值
對于可變的序列來說,+=,*=內部調用了可變序列對象的__iadd__方法或者__imul__方法
那么該可變序列就會就地改動,并不會指向新的對象,就是說他的id是不變的
l=[1,3,4]print(id(l))
l*=4
print(id(l))#60606088#60606088
對于不可變序列來說+=和*=會退一步的調用__add__,和__mul__方法
那么該方法會進行重新的賦值拼接操作,然后追加到新的元素中
l=(1,3,4)print(id(l))
l*=4
print(id(l))#43408192#43626216
對不可變序列進行重復拼接操作的話,效率會很低,因為每次都有一個新對象,而且解釋器需要把原來的對象中的元素先賦值到新的對象里,然后再追加新的元素
+=的一個有趣例子:
t=(1,2,[30,40])
t[2]+=[50,60]#運行后,代碼報錯
#但是再打印t發現元素已經修改了#我們可以用捕捉異常來看
try:
t=(1,2,[30,40])
t[2]+=[50,60]exceptException as e:print(t)#(1, 2, [30, 40, 50, 60])
我們可以看到t[2]=t[2]+[50,60],先進行列表的相加,我們知道這一步是可以實現的,但是當我們賦值到t[2]的時候,因為t是一個元組是不可以修改的序列當然就報錯了
但是我們的t[2]+[50,60]這一部已經執行了,就是說t[2]列表對象的值已經被修改了
所以在報錯的同時元組也被修改了
bisect模塊
bisect模塊包含兩個主要函數,bisect和insort,兩個函數都是利用二分查找算法來在有序的序列中查找或者插入元素
用bisect來搜索
bisect(haystack,needle)在haystack(干草垛)里搜索needle(針)的位置,haystack必須是一個有序的序列.
例子:
importbisectimportsys
HAYSTACK=[1,4,5,6,8,12,15,20,21,23,23,26,29,30]
NEEDLES=[0,1,2,5,8,10,22,23,29,30,31]
ROW_FMT='{0:2d}@{1:2d} {2}{0:<2d}'
defdemo(bisec_fn):for needle inreversed(NEEDLES):
position=bisec_fn(HAYSTACK,needle)
offset= position* '|'
print(ROW_FMT.format(needle,position,offset))if __name__ == '__main__':if sys.argv[-1] == 'left':
bisect_fn=bisect.bisect_leftelse:
bisect_fn=bisect.bisectprint('HAYSTACK->',' '.join('%2d'%n for n inHAYSTACK))
demo(bisect_fn)
HAYSTACK-> 1 4 5 6 8 12 15 20 21 23 23 26 29 30
31@14 | | | | | | | | | | | | | |31
30@14 | | | | | | | | | | | | | |30
29@13 | | | | | | | | | | | | |29
23@11 | | | | | | | | | | |23
22@ 9 | | | | | | | | |22
10@ 5 | | | | |10
8@ 5 | | | | |8
5@ 3 | | |5
2@ 1 |2
1@ 1 |10@ 0 0
用bisect.insort插入新元素
在得到一個有序的序列之后,我們插入新元素仍然想保持有序的序列
那么我們用insort(seq,item)把變量item插入到seq中,并保持seq升序順序.
例子:
importrandomimportbisect
SIZE=7my_list=[]for i in range(SIZE*2):
new_item= random.randrange(SIZE * 3)
bisect.insort(my_list,new_item)print('%2d ->'%new_item,my_list)
容器的選擇
并不是選擇序列容器的時候都要選擇列表,雖然列表很強大,但是我們在選擇的時候需要根據我們的需求來加以衡量.
比如我們存放一個1000萬個浮點數的話,數組(array)的效率要高得多.因為數據背后存的并不是float對象,而是數字的機器翻譯也就是字節表述.
當然如果要頻繁的對序列做先進先出的操作,那么可以用deque雙端隊列.
總結
以上是生活随笔為你收集整理的流畅的python目录_流畅的python python 序列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《地下城与勇士》中掉落的“密封”装备有什
- 下一篇: python的函数_Python 返回函