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》
歡迎大家評論交流,作者水平有限,如有錯誤,歡迎指出