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》
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出