Python進階6——序列操作

1.序列的拼接和複製

Python中使用+對序列進行拼接,使用*對序列進行復制

s=str(1234)
l=list(range(2,13))
print(s,l)
print('----------------')
print(s*2, 3*s)#將字符串s複製並打印
print('----------------')
print(l*2)#將列表複製生成一個新的列表並打印
print('----------------')
print(s+'1234567890')#字符串拼接
print('----------------')
print(l+2*l)#列表拼接
print('----------------')
print(l,s)

上述代碼的第三行和最後一行表明,列表的拼接和複製操作並不會改變原來的序列,而是生成一個全新的列表

 

*構建嵌套列表和列表解析式生成嵌套列表兩種方法

mat1=[[0]*3 for i in range(3)]
print(mat1)
mat2=[[0]*3]*3
print(mat2)

mat1[1][2]=2
print(mat1)
mat2[1][2]=3
print(mat2)

前四行代碼的打印結果看起來並沒有不同,但是當對嵌套列表中的元素進行修改時,可以看到這兩個嵌套列表只是形式一樣

當把mat1和mat2的元素的id打印出來後,可以知道其中的原因

for ele in mat1:
	print(id(ele))

for ele in mat2:
	print(id(ele))

可見,mat1中的三個子列表分別指向了不同的地址空間,然而mat2中的三個子列表卻指向了同一個地址空間

所以,當對mat1中的某個元素進行修改時,不會牽一髮而動全身,而對mat2進行修改時,會導致其他子列表對應位置的元素也跟着改變

所以,使用列表解析式方式產生的嵌套列表穩定,而使用*生成的嵌套列表不穩定

 

序列的*=和+=

當對象執行*=時,會自動調用魔術方法__imul__,如果沒有實現該方法,會調用__mul__,此時,a*=b等價於a=a*b,+=也是一樣

當元組與*=和+=組合時,會產生新的元組

l=list(range(1,5))
t=tuple(range(1,5))
print(l,t)
print(id(l), id(t))
l*=3
t*=3
print(l,t)
print(id(l), id(t))

可見,當對列表執行*=操作後,l指向的地址空間沒有變,而元組執行*=操作後,卻產生了新的元組,原因就是元組的不可變性

 

Python知識點3——列表操作中,最後寫到元組可以被整體修改,其實並不是整體修改,只是產生了一個新的元組,然後對象指向了新的元組的地址空間,因爲元組是不可變的

t2=(1,23,4)
print(id(t2))
t2=(3)
print(id(t2))

 

元組真的不可改變嗎

當元組中的元素含有可變對象時,元組可以改變

t3=(1,2,3,[4,5])
t3[3]+=[6,7]

通過交互模式可以發現,雖然對元組中的列表進行拼接時顯示了error,但是元組最終還是被改變了

一是因爲+=和*=是原子操作(要不一部不執行,要不全都執行,這裏+=操作全部執行結束,且中間不會因爲其他軟硬件原因導致該操作出現異常),二是因爲列表是可變的

 

列表的排序,列表的排序見博客Python知識點2——列表基礎

關於排序中的key參數見博客Python進階1——一摞紙牌

 

bisect模塊管理已排序的序列

bisect模塊主要是通過二分查找來查找或者插入元素,主要的函數有bisect和insort

bisect的作用是返回插入元素的插入位置的索引

 

舉例

import bisect
import sys

listnums=[1,4,5,6,8,20,23,23,26,29,30]#已經拍好順序的列表
insertnums=[0,1,2,5,8,10,22,23,29,30,31]#要插入的元素

def demo(bisect_fn):#傳入函數名
	print("demo")
	for i in insertnums:
		pos=bisect_fn(listnums, i)
		print(pos)#打入插入元素的插入位置的索引

print(__name__)
if __name__ == '__main__':
	if sys.argv[-1]=='left':#最後一個命令行參數,類似於C++中的argc和argv
		bisect_fn=bisect.bisect_left
	else: 
		bisect_fn=bisect.bisect
	print(bisect_fn.__name__)#打印調用的函數名
	demo(bisect_fn)

執行 python3 seoperation.py的結果

bisect模塊中的bisect函數是bisect_right函數名別名,將插入元素的位置放置於和它相等的元素的右邊

因爲0比1小,所以,0將被放置在listnum中索引爲0的位置,1和1相等,所以1將被放置與listnum中1的右邊,打印出的索引爲1,以此類推

執行python3 seoperation.py left的結果

bisect模塊中的bisect_left函數的意思是將插入元素的位置放置於和它相等的元素的左邊,所以1將被放置與listnum中1的左邊,打印出的索引爲0

 

上述代碼中的if __name__ == '__main__':是一個判斷,如果直接運行當前文件,那麼變量__name__的值就是'__main__',如果當前文件被作爲一個模塊導入,那麼__name__的值就不是'__main__'

所以if __name__ == '__main__':用來區分當前文件是否作爲一個模塊被導入,如果不作爲模塊,那麼if __name__ == '__main__':下面的代碼執行,否則if __name__ == '__main__':下面的代碼不執行

 

給定一個分數,找到對應的成績

def getgrade(score, section=[60,70,80,90], level='FDCBA'):
	i=bisect.bisect(section, score)
	return level[i]

res=[getgrade(score) for score in range(50,110,10)]
print(res)

總體思路就是通過bisect.bisect(section, score)返回分數對應的level索引,然後返回

 

用bisect.insort向序列中插入新元素

使用insort插入元素時,會保持序列有序

import bisect
listnums=[1,4,5,6,8,20,23,23,26,29,30]
bisect.insort(listnums, 10)
print(listnums)

 

參考:

《流暢的Python》

 

歡迎大家評論交流,作者水平有限,如有錯誤,歡迎指出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章