深入理解python中的切片

本文详细介绍了Python中的切片操作,包括切片的语法、默认值以及步长的正负影响。同时,文章讨论了切片在赋值时的行为,特别是当切片出现在等号左边时,如何修改原始列表。还提到了空切片的使用以及`del`语句的原理。最后,文章通过例子展示了列表切片赋值时如何改变原始列表的特性,这与直接赋值给单个索引有所不同。
摘要由CSDN通过智能技术生成

切片的基本使用
sequence[start:stop:step]

start:切片的起始索引,它将包括此索引处的元素,除非它与 stop 相同,默认为 0,即第一个索引。
stop:切片的结束索引,它不包括此索引处的元素,默认为被切片序列的长度,即直到并包括结束。
step:步长,默认为 1。如果它是负数,则从后往前进行切片。

省略开始索引时,默认值为 0,省略结束索引时,默认为到字符串的结尾
同样支持负数的索引,标号从最后一个元素往前依次为-1,-2,…
根据步长的正负的不同,切片表示将有所差异:

[a:b:c]
len = length of string, tuple or list
c – default is +1. The sign of c indicates forward or backward, absolute value of c indicates steps. Default is forward with step size 1. Positive means forward, negative means backward.
a – When c is positive or blank, default is 0. When c is negative, default is -1.
b – When c is positive or blank, default is len. When c is negative, default is -(len+1).

when step is positive

>>> seq[:]                # [seq[0],   seq[1],          ..., seq[-1]    ]
>>> seq[low:]             # [seq[low], seq[low+1],      ..., seq[-1]    ]
>>> seq[:high]            # [seq[0],   seq[1],          ..., seq[high-1]]
>>> seq[low:high]         # [seq[low], seq[low+1],      ..., seq[high-1]]
>>> seq[::stride]         # [seq[0],   seq[stride],     ..., seq[-1]    ]
>>> seq[low::stride]      # [seq[low], seq[low+stride], ..., seq[-1]    ]
>>> seq[:high:stride]     # [seq[0],   seq[stride],     ..., seq[high-1]]
>>> seq[low:high:stride]  # [seq[low], seq[low+stride], ..., seq[high-1]]
lst = [1,2,3,4,5]
lst[1:] #>>[2,3,4,5]
lst[:4] #>>[1, 2, 3, 4]
lst[-4:4:2]#>>[2,4]   #从倒数第四个到第四个元素,步长为2

when step is negative

>>> seq[::-stride]        # [seq[-1],   seq[-1-stride],   ..., seq[0]    ]
>>> seq[high::-stride]    # [seq[high], seq[high-stride], ..., seq[0]    ]
>>> seq[:low:-stride]     # [seq[-1],   seq[-1-stride],   ..., seq[low+1]]
>>> seq[high:low:-stride] # [seq[high], seq[high-stride], ..., seq[low+1]]
lst = [1,2,3,4,5]
lst[::-1]  #>>[5, 4, 3, 2, 1]
lst[-3::-1]  #>>[3, 2, 1]
lst[-2:1:-1] #>>[4, 3]  从倒数第二个到第三个元素

并且相比索引,索引越界会报错,而切片会自动处理越界索引

lst = [0,1,2,3,4]
lst[3:9] #>>[3,4]
lst[9:] #>>[]

今天在回顾切片这个知识点的时候,又明确了一个概念就是对列表的切片其实都是返回一个新的浅拷贝对象。

a = [1, [0,2], 3]
b = a[:2]
a[1][0] = 4
b  #>>[1, [4, 2]]

进而对整个列表的浅拷贝(复制列表)即为

a = [1, [0,2], 3]
b = a[:]
b #>>[1, [0, 2], 3]

明确了切片是返回一个新的对象后,产生了一个疑问也是在stackflow中看到了一样的问题即

a = [1, 2, 3]
a[0:2] = [4, 5]
print(a)
# 输出
# [4, 5, 3] 

为什么这里a[0:2]可以修改原始列表,它不是应该是新的列表对象吗?

该问题下的一个回答:
I came across the same question before and it’s related to the language specification. According to assignment-statements,

  1. If the left side of assignment is subscription, Python will call __setitem__ on that object.a[i] = x is equivalent to .a.__setitem__(i, x)
  2. If the left side of assignment is slice, Python will also call __setitem__, but with different arguments: a[1:4]=[1,2,3]is equivalent to a.__setitem__(slice(1,4,None), [1,2,3])
    That’s why list slice on the left side of ‘=’ behaves differently.

大致意思就是python中切片出现在赋值符号 = 的左边行为会发生改变,在左边调用__setitem__ 方法,而在 = 的右边则是调用__getitem__方法

python官方文档给出了解释
如果目标为一个切片:引用中的原型表达式会被求值。 它应当产生一个可变序列对象(例如列表)。 被赋值对象应当是一个相同类型的序列对象。 接下来,下界与上界表达式如果存在的话将被求值;默认值分别为零和序列长度。 上下边界值应当为整数。 如果某一边界为负值,则会加上序列长度。 求出的边界会被裁剪至介于零和序列长度的开区间中。 最后,将要求序列对象将切片替换为指定序列的项目。 切片的长度可能与指定序列的长度不同,这会在目标序列允许的情况下改变目标序列的长度。(目标即=左边,被赋值对象即=右边)

解释一下就是切片出现在 = 左边时,并没有创建一个新的对象而是将这个被赋值后的切片插入到原始的序列对象当中,并且允许被赋值对象的序列长度大于切片的长度

a = [1, 2, 3]
a[0:2] = [4,5,6,7]
print(a)
# 输出
# [4, 5, 6, 7, 3]

但还需注意的一点是我们还可以改变空切片,相当于在该位置中插入元素

a = [1, 2, 3]
a[1:1]
#输出:[]
a[1:1] = [4,5,6]
print(a)
#输出[1, 4, 5, 6, 2, 3]

同样python官方文档也解释了 del a[:]的原理

属性引用、抽取和切片的删除会被传递给相应的原型对象;删除一个切片基本等价于赋值为一个右侧类型的空切片(但即便这一点也是由切片对象决定的)。
del a[:]等价于a[:] = []


参考:
https://stackoverflow.com/questions/10623302/how-does-assignment-work-with-list-slices
https://stackoverflow.com/questions/509211/understanding-slicing
https://docs.python.org/zh-cn/3/reference/simple_stmts.html#the-del-statement

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值