黑马程序员技术交流社区

标题: 【上海校区】贝斯狸的 Python 之旅 -- 深入切片操作及原理 [打印本页]

作者: 不二晨    时间: 2018-8-1 09:30
标题: 【上海校区】贝斯狸的 Python 之旅 -- 深入切片操作及原理
我首先通过 input() 函数,接收了外部输入字符串,然后通过 list 函数的切片,实现了回文数,代码真的好简洁,我自己都佩服我自己,我也不知道小组长会问我切片原理,我好无奈呀。
s = input()if s == s[::-1]:    print("True")else:    print("False")>>> abcbaTrue复制代码

什么是列表切片?切片操作不是列表特有的,python 中的有序序列都支持切片,如字符串,元组。
切片的返回结果类型和切片对象类型一致,返回的是切片对象的子序列,如:对一个列表切片返回一个列表,
字符串切片返回字符串。
切片生成的子序列元素是源版的拷贝。因此切片是一种浅拷贝。


切片的图示分析li=["A","B","C","D"]# 格式:li[start : end : step]    # start 是切片起点索引,end 是切片终点索引,但切片结果不包括终点索引的值。step 是步长默认是 1。# [start : end : step) 左开右闭t=li[0:3]        ["A","B","C"]       #起点的0索引可以省略,t=li[:3]t=li[2: ]        ["C","D"]           #省略end,则切到末尾t=li[1:3]        ["B","C"]t=li[0:4:2]      ["A","C"]                #从li[0]到li[3],设定步长为2。          复制代码在 step 的符号一定的情况下,start 和 end 可以混合使用正向和反向索引,无论怎样,你都要保证
start 和 end 之间有和 step 方向一致元素间隔,否则会切出空列表。
Case 1t=li[0:2]                t=li[0:-2]                t=li[-4:-2]                t=li[-4:2]
上面的结果都是一样的:t 为 ["A","B"]。


Case 2t=li[-1:-3:-1]                t=li[-1:1:-1]                t=li[3:1:-1]                t=li[3:-3:-1]
上面的结果都是一样的:t 为 ["D","C"]。


Case 3t=li[-1:-3]        t=li[-1:1]                t=li[3:1]                t=li[3:-3]
都切出空列表。


同时,step 的正负决定了切片结果的元素采集的先后。
省略 start  和 end 表示以原列表全部为目标。
t=li[::-1]     t--->["C","B","A"]     #反向切,切出全部。
t=li[:]        t--->["A","B","C","D"]   #正向切全部。


切片原理小狸,学习一件事物,先学习它的表象,然后分析它的内在实现,最后查看源代码仔细推敲它到底是怎么实现的。
需要注意的是,列表切片产生的是列表的副本,与原列表不是同一份空间。
x=[1,2,3]y=x[:]x[0]=-1print(y) #输出[1,2,3]复制代码切片写操作在2后面插入若干个元素,应该用列表
#case 1>>> x=[1,2,3,4,5]>>> x[2:0]=100  #在2后面插入若干个元素,应该用列表Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: can only assign an iterable>>> x[2:0]=[100]>>> x[1, 2, 100, 3, 4, 5]#case 2>>> x[2:4]=NoneTraceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: can only assign an iterable>>> x[2:4]=[None]>>> x[1, 2, None, 5]复制代码删除切片
>>> del x[2:3]  #删除切片>>> x[1, 2, 3, 4, 5]复制代码对于切片x[from:to],会进行预处理to=max(from+1,to)
>>> x=[1,2,3,4,5]>>> x[2:1]=[100] #对于切片x[from:to],会进行预处理to=max(from+1,to)>>> x[1, 2, 100, 3, 4, 5]复制代码对于切片del操作,如果from>to,不执行任何操作
>>> del x[2:0] >>> x[1, 2, 100, 3, 4, 5]>>> del x[2:1]>>> x[1, 2, 100, 3, 4, 5]>>> del x[2:3]>>> x[1, 2, 3, 4, 5]复制代码切片原理解析通过指定下标的方式来获得某一个数据元素,或者通过指定下标范围来获得一组序列的元素,这种访问序列的方式叫做切片。有些地方也把它称之为分片。
先从底层分析切片运算:
list 的切片,内部是调用 __getitem__,__setitem__,__delitem__ 和 slice 函数。而 slice 函数又是和 range() 函数相关的。
给切片传递的键是一个特殊的 slice 对象。该对象拥有可描述所请求切片方位的属性。
a = [1,2,3,4,5,6]x = a [ 1 : 5 ]                # x = a.__getitem__(slice( 1, 5, None))a [ 1 : 3 ] = [10, 11, 12 ]    # a.__setitem__(slice(1, 3, None), [ 10, 11, 12 ])del a [ 1 : 4 ]                # a.__delitem__(slice(1, 4, None))复制代码看看代码具体实现
def between(beg, end, mid):        # 判断mid是否位于begin和end之间        return end > mid >= beg or end < mid <= beg def get_slice(a, beg, end, delta=1):         # 数组切片get方式         if delta == 0:         raise ValueError("slice step cannot be 0")         # 将负数下标转化一下         if beg < 0:         beg += len(a)         if end < 0:         end += len(a)         # 如果转化完成之后依然不在合法范围内,则返回空列表         if beg < 0 and end < 0 or beg >= len(a) and end >= len(a):         return []         # 如果方向不同,则返回空列表         if (end - beg) * delta <= 0:         return []         # 将越界的部分进行裁剪         beg = max(0, min(beg, len(a) - 1))         end = max(-1, min(end, len(a)))         ans = []         i = beg         while between(beg, end, i):                  ans.append(a)                  i += delta         return ans def set_slice(a, li, beg, end, delta=1):         if delta == 0:         raise ValueError("slice step cannot be 0")         if delta == 1:          # 如果delta==1,那么li的长度可以随意          if beg < 0:         beg += len(a)          if end < 0:         end += len(a)          beg = max(0, min(beg, len(a) - 1))          end = max(-1, min(end, len(a)))          for i in range(beg, end):                   del a[beg]          for i in reversed(li):                   a.insert(beg, i)        else:          # delta!=1,相当于替换          if len(get_slice(a, beg, end, delta)) != len(li):         raise ValueError("array don't match")          if len(li) == 0:         return          if beg < 0:         beg += len(a)          if end < 0:             end += len(a)          beg = max(0, min(beg, len(a) - 1))          # 用li中的全部元素逐一替换          for ind, value in enumerate(li):                   a[ind * delta + beg] = value复制代码

总结
1、本次贝斯狸的 Python 学习之旅是一次尝试,想让程序员学习生活变得更加有乐趣,也算满足了我的愿望,重拾 PhotoShop,后面还会更新更多有趣可爱的对话,轻松实现学习生活两不误。
2、学习知识是一个循序渐进的过程,正如小狸一样,学会了使用,但是却没有深入,小组长随机抽查便中了招,所以我们要时刻保持好奇心,凡事多问个为什么?这样才能进步。


作者:蒋志碧
链接:https://juejin.im/post/5b5a0c316fb9a04fb4016e19




作者: 不二晨    时间: 2018-8-1 10:21

奈斯,很赞
作者: 梦缠绕的时候    时间: 2018-8-2 16:26





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2