Python进阶04-序列切片和增量的高级用法

本文深入探讨Python中切片操作的高级用法,包括忽略最后一个元素的原因、利用切片进行序列分割、对象切片、多维切片及省略符号的使用。通过实例展示切片在数据解析和序列修改中的应用,以及列表推导与增量赋值的效率对比。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

切片的高级用法

为什么忽略最后一个元素

在切片的操作中都不会包含最后一个元素,比如b[0:3]:b[0],b[1],b[2]。这样做的目的是:符合
Python、C 和其他语言里以 0 作为起始下标的传统。
好处有:

  • 当只有最后一个位置信息时,我们也可以快速看出切片和区间里有几个元素array[:5],返回5个元素
  • 当起止位置信息都可见时,计算出切片和区间的长度:a[1:4],4-1=3,count = stop-start
  • 利用任意一个下标来把序列分割成不重叠的两部分:a[:x],a[x:]
l = [1,2,3,4,5,6,7]
#只有最后一个位置信息
print(l[:4])
#当起止位置信息都可见
print(l[2:4])
# 分割成不重叠
print(l[:2])
print(l[:2])
print(l[:3])
print(l[:3])

[1, 2, 3, 4]
[3, 4]
[1, 2]
[1, 2]
[1, 2, 3]
[1, 2, 3]

对对象进行切片

s[a?️c] 的形式对 s 在 a 和 b 之间以 c 为间隔取值。c 的值还可以为负,负值意味着反向取值。
a?️c 这种用法只能作为索引或者下标用在 [] 中来返回一个切片对象:slice(a, b, c)
给切片命名:SKU = slice(0,6)

#间隔取值切片
s = 'feifei'
# 从第一个取到最后一个,间隔为3
print(s[::3])
# 反向从第一个取到最后一个,间隔为0
# 这个可以用来反向
print(s[::-1])
print(s[::-2])

ff
iefief
ife
#利用切片对象来实现数据的解析

invoice = """ 
... 0.....6................................40........52...55........
... 1909  Pimoroni PiBrella                    $17.50    3    $52.50 
... 1489  6mm Tactile Switch x20                $4.95    2     $9.90 
... 1510  Panavise Jr. - PV-201                $28.00    1    $28.00 
... 1601  PiTFT Mini Kit 320x240               $34.95    1    $34.95
..."""

SKU = slice(0,6)
DESCRIPTION = slice(6,40)
UNIT_PRICE = slice(40,52)
QUANTITY = slice(52,55)
ITEM_TOTAL = slice(55,None)
line_items = invoice.split('\n')[2:]
for item in line_items:
    #print(item)
    print(item[UNIT_PRICE],item[DESCRIPTION])
       $17.5 09  Pimoroni PiBrella             
        $4.9 89  6mm Tactile Switch x20        
       $28.0 10  Panavise Jr. - PV-201         
       $34.9 01  PiTFT Mini Kit 320x240        

多维切片和省略

多维切片
[] 运算符里还可以使用以逗号分开的多个索引或者是切片
二维的 numpy.ndarray 就可以用 a[i,j] 这种形式来获取,抑或是用 a[m:n,k:l]的方式来得到二维切片

Python 内置的序列类型都是一维的,因此它们只支持单一的索引,成对出现的索引是没有用的。

省略
省略(ellipsis)的正确书写方法是三个英语句号(…)

  • 也可以用在函数的参数清单中,比如 f(a, …, z),或 a[i:…]
  • 在 NumPy 中,… 用作多维数组切片的快捷方式。如果 x 是四维数组,那么 x[i, …] 就是 x[i, :, :, :] 的缩写。

给切片赋值

把切片放在赋值语句的左边,或把它作为 del 操作的对象,我们就可以对序列进行嫁接、切除或就地修改操作。

注意
如果赋值的对象是一个切片,那么赋值语句的右侧必须是个可迭代对象。即便只有单独一个值,也要把它转换成可迭代的序列。

# 给切片赋值
l = list(range(10))
print(l)
l[2:5] = [20,30]
print(l)
del l[5:7]
print(l)
l[3::2] = [11,22]
print(l)
l[2:5] = [100]
print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 20, 30, 5, 6, 7, 8, 9]
[0, 1, 20, 30, 5, 8, 9]
[0, 1, 20, 11, 5, 22, 9]
[0, 1, 100, 22, 9]

对序列使用+和*

通常 + 号两侧的序列由相同类型的数据所构成,在拼接的过程中,两个被操作的序列都不会被修改,Python 会新建一个包含同样类型数据的序列来作为拼接的结果。

如果想要把一个序列复制几份然后再拼接起来,更快捷的做法是把这个序列乘以一个整数。

+ 和 * 都遵循这个规律,不修改原有的操作对象,而是构建一个全新的序列。

# 序列使用+和*
l1 = [1,2,3]
l2 = [4,5,6]
print(l1+l2)
print(5 * 'abcd')
[1, 2, 3, 4, 5, 6]
abcdabcdabcdabcdabcd

建立由列表组成的列表

有时我们会需要初始化一个嵌套着几个列表的列表,最好的选择是使用列表推导.

列表推导写法
board = [['_'] * 3 for i in range(3)]

迷惑的写法
weird_board = [['_'] * 3] * 3

两者的区别:

  • 列表推导的写法,表示每次循环都会新建一个列表元素
  • 迷惑的写法,表示同一个元素复制3次,实际上是指向同一个列表
  • 迷惑的写法中,当需要修改的时候,会同时被修改,因为这 3 个引用指向的都是同一个列表
# 使用列表推导来创建嵌套列表
# ['_'] * 3 每次循环都创建一次,
board = [['_'] * 3 for i in range(3)]
print(board)
board[1][2] = 'X'
print(board)
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]
# 列表推导等同做法
borad = []
for i in range(3)
    sub = ['_'] * 3 # 每次都新建3个元素
    borad.append(sub)
# 迷惑的写法
weird_board = [['_'] * 3] * 3
print(weird_board)
weird_board[1][2] = 'X'
print(weird_board)
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
[['_', '_', 'X'], ['_', '_', 'X'], ['_', '_', 'X']]
# 迷惑的写法等同做法
borad = []
sub = ['_'] * 3 # 只新建一次
for i in range(3)
    borad.append(sub) #每次都添加同一个引用

序列的增量赋值(+=/*=)

可变序列与不可变序列的增量赋值

**增量赋值:**对第一个对象进行操作,如下例子,对a进行操作。
a += b

增量赋值的原理: 使用的特殊方法是 iadd(用于“就地加法”),如果没有实现这个方法就会退一步调用__add__方法。
对于上面的例子:

  • 如果a实现了__iadd__ 方法,就会调用该方法,如果a是可变序列,就像调用了 a.extend(b) 一样
  • 如果a没有实现__iadd__ 方法,a += b 这个表达式的效果就变得跟 a = a + b,这样a+b会创建一个新的对象,然后赋值给a,a就关联一个新的对象地址了。

总体来讲,可变序列一般都实现了 iadd 方法,因此 += 是就地加法。而不可变序列根本就不支持这个操作,对这个方法的实现也就无从谈起。对不可变序列进行重复拼接操作的话,效率会很低,因为每次都有一个新对象。

# 可变序列的 *=
l = [1,2,3]
print(id(l))
l *=2
print(l)
print(id(l)) #id并未改变说明就地增加

t = (1,2,3)
print(id(t))
t *=2
#t +=t
print(t)
print(id(t)) # id被修改,创建了新的对象
2163791378760
[1, 2, 3, 1, 2, 3]
2163791378760
2163788018744
(1, 2, 3, 1, 2, 3)
2163791314280

关于+=的谜题

对于如下的例题,出现的结果如下:

t = (1,2,[30,40])
t[2] +=[50,60] 
  • t 变成 (1, 2, [30, 40, 50, 60])。
  • 因为 tuple 不支持对它的元素赋值,所以会抛出 TypeError 异常。

如何避免该错误:

  • 不要把可变对象放在元组里面。
  • 增量赋值不是一个原子操作。我们刚才也看到了,它虽然抛出了异常,但还是完成了操作。
  • 写成 t[2].extend([50, 60]) 就能避免这个异常
t = (1,2,[30,40])
t[2] +=[50,60] 
#print(t)
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-2-d433547e6778> in <module>
      1 t = (1,2,[30,40])
----> 2 t[2] +=[50,60]
      3 print(t)


TypeError: 'tuple' object does not support item assignment
print(t)
(1, 2, [30, 40, 50, 60])


分享关于人工智能,机器学习,深度学习以及计算机视觉的好文章,同时自己对于这个领域学习心得笔记。想要一起深入学习人工智能的小伙伴一起结伴学习吧!扫码上车!

瓦力人工智能 - 扫码上车

### Python 切片使用方法 #### 基础语法 Python切片功能允许通过指定起始索引、结束索引以及步长来获取序列中的子集。基本语法如下: ```python sequence[start:end:step] ``` - `start` 表示开始的位置,默认为 0。 - `end` 表示结束的位置(不包括该位置),默认为序列长度。 - `step` 是间隔数,默认为 1。 当只提供单个参数时,表示从该位置到序列末尾;两个参数则定义了一个范围[^1]。 #### 字符串切片实例 对于字符串而言,可以轻松提取特定部分的内容: ```python text = "hello world" substring = text[0:5] # 提取出 'hello' print(substring) ``` 此代码片段展示了如何利用正向索引来选取前五个字符组成的子串[^2]。 #### 插入元素至列表中某处 值得注意的是,除了用于读取数据外,还可以借助切片的方式修改现有结构内的项目。例如,在给定位置批量插入多个新项: ```python my_list = ["a", "b", "d"] my_list[2:2] = ["c"] # 在第三个位置之前加入 'c' ,即 my_list 变成 ['a', 'b', 'c', 'd'] print(my_list) ``` 这里采用 `[n:n]` 形式的切片作为目标区域,并赋值一个新的可迭代对象实现插入操作。 #### 步长的应用——逆序遍历与筛选奇偶数 设置负数作为 step 参数能够改变方向,从而支持倒叙访问元素。另外,配合 start end 控制边界条件,可用于高效过滤出符合条件的数据点,比如仅保留数组里的奇数位成员: ```python numbers = [0, 1, 2, 3, 4, 5, 6] odd_numbers = numbers[1::2] # 获取所有奇数索引对应的值 [1, 3, 5] reversed_text = "abcdefg"[::-1] # 将整个字符串反转得到 'gfedcba' print(odd_numbers) print(reversed_text) ``` 上述例子分别演示了基于固定增量抽取子列完全翻转原始顺序两种情况下的应用方式[^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值