查看: 230|回复: 0

Python列表切片高级技巧:原地修改、分页与slice对象

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
列表切片是 Python 很有代表性的语法。它不只是“取一段”,还能原地修改列表长度、反转、分页、批量赋值,并经常替代循环和边界判断。下面按语法规则、切片赋值、工程场景、slice 对象和性能陷阱展开。

一、完整语法与默认值
  1. lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  2. print(lst[2:7:2])   # [2, 4, 6]
  3. print(lst[8:2:-2])  # [8, 6, 4]
复制代码
语法为 lst[start:stop:step]。start 包含,stop 不包含,step 默认 1 且不能为 0。step 大于 0 时,start 默认 0,stop 默认 len(lst);step 小于 0 时,start 默认 -1(最后一个元素),stop 默认 -len(lst)-1,所以 lst[::-1] 与 lst[-1:-11:-1] 等价。切片按 start、start+step、start+2*step……直到达到或越过 stop。例如 lst[1:6:2] 取索引 1、3、5;lst[6:1:-2] 取索引 6、4、2。

二、不越界、浅拷贝与 NumPy 视图差异
切片遇到越界不会报错:lst[0:100] 自动截断,lst[10:20] 返回空列表,而索引 lst[100] 会抛 IndexError。边界模糊时优先用切片。切片创建浅拷贝:original[:] 是新列表,修改原列表不影响副本;嵌套列表的内层对象仍共享,需要 copy.deepcopy 才能完全独立。Python 列表切片返回新列表,不是视图;NumPy 数组切片是视图,修改 arr_view 会同步影响原数组。从列表切到 NumPy 时要特别注意这个兼容性差异。

三、切片赋值:原地修改列表
  1. nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  2. nums[3:7] = [30, 40, 50, 60]
  3. nums[3:7] = [30, 40, 50, 60, 70, 80]  # 列表可变长
  4. nums[3:9] = [300]                      # 列表可变短
  5. nums[2:5] = []                         # 删除一段
  6. nums[1:1] = [2, 3, 4]                  # 在索引 1 处插入
  7. nums[:0] = [-1, 0]                     # 开头插入
  8. nums[len(nums):] = [10, 11]            # 末尾插入
复制代码
带步长的切片赋值有严格限制:nums[::2] = [10, 20, 30] 合法,因为右侧长度与切片位置数量一致;少一个或多一个会抛 ValueError: attempt to assign sequence of size 2 to extended slice of size 3。步长为 1 的切片赋值不受此限,可以改变列表长度。删除时 del lst[::2] 与 lst[::2] = [] 效果相同。

四、常用技巧
反转序列:lst[::-1] 最常用但会创建新列表;list.reverse() 原地反转,额外内存 O(1);reversed(lst) 返回懒迭代器,同样 O(1) 额外内存。字符串也可用 text[::-1] 反转。
浅拷贝写法:original[:]、original.copy()、list(original)。实测 .copy() 通常最快,[:] 次之,list() 最慢。
降采样:lst[::factor],例如 list(range(100))[::10] 得到 [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]。
旋转和交换可借助切片赋值原地完成:
  1. def rotate_left(lst, k):
  2.     k %= len(lst)
  3.     lst[:] = lst[k:] + lst[:k]
  4. def rotate_right(lst, k):
  5.     k %= len(lst)
  6.     lst[:] = lst[-k:] + lst[:-k]
  7. def swap_halves(lst):
  8.     mid = len(lst) // 2
  9.     lst[:] = lst[mid:] + lst[:mid]
复制代码
压缩列表:del lst[::2] 删除偶数索引位置,del lst[1::2] 删除奇数索引位置,lst[3:-3] = [] 保留前 3 个和后 3 个。

五、工程场景:分页、截断、批量赋值与矩阵遍历
分页可直接用切片:
  1. def paginate(items, page, page_size):
  2.     start = (page - 1) * page_size
  3.     end = start + page_size
  4.     return items[start:end]
复制代码
页码越界时切片返回空列表,不会抛异常。带信息分页可计算 total_pages = (total + page_size - 1) // page_size,再用 max/min 修正 page,返回 items[start:end] 以及 has_prev、has_next。
文本截断:
  1. def truncate(text, max_length, ellipsis='...'):
  2.     if len(text) <= max_length:
  3.         return text
  4.     return text[:max_length - len(ellipsis)] + ellipsis
  5. def summary(text, n=100):
  6.     return text[:n]
复制代码
尾部日志可用 lines = text.splitlines(),再取 lines[-n:]。
批量赋值:
  1. nums = [0] * 10
  2. nums[:5] = [1] * 5
  3. nums[::2] = [1] * 5
复制代码
棋盘格可先构造 row_template[::2] 和 row_template[::-1],再按行奇偶复制。螺旋遍历矩阵则利用 matrix[1:] 去首行,再用 zip(*matrix) 转置并反转行,实现逆时针旋转:
  1. def spiral_order(matrix):
  2.     result = []
  3.     while matrix:
  4.         result.extend(matrix[0])
  5.         matrix = matrix[1:]
  6.         if matrix:
  7.             matrix = [list(row) for row in zip(*matrix)][::-1]
  8.     return result
复制代码

六、slice 对象与自定义类
slice(start, stop, step) 可以创建可复用的切片对象。s = slice(2, 8, 2) 后,lst 与 lst[2:8:2] 完全一样。slice 对象有 start、stop、step 属性,indices(len) 能把参数规范到合法范围:slice(5, 100, 2).indices(10) 得到 (5, 10, 2),slice(-100, 3, 1).indices(10) 得到 (0, 3, 1)。自定义类可实现 __getitem__、__setitem__、__delitem__ 来支持切片:
  1. class DataSeries:
  2.     def __init__(self, data):
  3.         self._data = list(data)
  4.     def __getitem__(self, key):
  5.         if isinstance(key, slice):
  6.             start, stop, step = key.indices(len(self._data))
  7.             result = [self._data[i] for i in range(start, stop, step)]
  8.             return DataSeries(result)
  9.         elif isinstance(key, int):
  10.             return self._data[key]
  11.         raise TypeError('不支持的索引类型:' + str(type(key)))
  12.     def __setitem__(self, key, value):
  13.         self._data[key] = value
  14.     def __delitem__(self, key):
  15.         del self._data[key]
  16.     def __len__(self):
  17.         return len(self._data)
复制代码

七、性能与陷阱
切片会创建新列表,内存消耗 O(n);原地反转 reverse() 额外内存 O(1),reversed() 是懒迭代。切片不越界,但索引越界会 IndexError。浅拷贝不等于深拷贝,嵌套对象会共享。Python 列表切片不是视图,NumPy 切片是视图,混用容易误改数据。带步长切片赋值长度必须匹配;step 不能为 0。分页函数要处理 page 越界,但切片本身返回空列表,无需异常捕获。

八、小结
切片的核心价值是边界安全、语法紧凑、能原地修改列表长度,并能通过 slice 对象复用规则。掌握默认值、步长方向、浅拷贝、NumPy 视图差异之后,可以在分页、文本截断、批量初始化、矩阵遍历和自定义容器中减少循环与边界判断。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-23 14:16 , Processed in 0.026413 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部