Python 的切片为什么不会索引越界?

简介: 切片(slice)是 Python 中一种很有特色的特性,在正式开始之前,我们先来复习一下关于切片的知识吧。切片主要用于序列对象中,按照索引区间截取出一段索引的内容。切片的书写形式:[i : i+n : m] ;其中,i 是切片的起始索引值,为列表首位时可省略;i+n 是切片的结束位置,为列表末位时可省略;m 可以不提供,默认值是 1,不允许为 0,当 m 为负数时,列表翻转。切片的基本含义是:从序列的第 i 位索引起,向右取到后 n 位元素为止,按 m 间隔过滤 。

切片(slice)是 Python 中一种很有特色的特性,在正式开始之前,我们先来复习一下关于切片的知识吧。

切片主要用于序列对象中,按照索引区间截取出一段索引的内容。

切片的书写形式:[i : i+n : m] ;其中,i 是切片的起始索引值,为列表首位时可省略;i+n 是切片的结束位置,为列表末位时可省略;m 可以不提供,默认值是 1,不允许为 0,当 m 为负数时,列表翻转。

切片的基本含义是:从序列的第 i 位索引起,向右取到后 n 位元素为止,按 m 间隔过滤

下面是一些很有代表性的例子,基本涵盖了切片语法的使用要点:

# @Python猫
li = [1, 4, 5, 6, 7, 9, 11, 14, 16]
# 以下写法都可以表示整个列表,其中 X >= len(li)
li[0:X] == li[0:] == li[:X] == li[:] == li[::] == li[-X:X] == li[-X:]
li[1:5] == [4,5,6,7] # 从1起,取5-1位元素
li[1:5:2] == [4,6] # 从1起,取5-1位元素,按2间隔过滤
li[-1:] == [16] # 取倒数第一个元素
li[-4:-2] == [9, 11] # 从倒数第四起,取-2-(-4)=2位元素
li[:-2] == li[-len(li):-2] == [1,4,5,6,7,9,11] # 从头开始,取-2-(-len(li))=7位元素
# 步长为负数时,列表先翻转,再截取
li[::-1] == [16,14,11,9,7,6,5,4,1] # 翻转整个列表
li[::-2] == [16,11,7,5,1] # 翻转整个列表,再按2间隔过滤
li[:-5:-1] == [16,14,11,9] # 翻转整个列表,取-5-(-len(li))=4位元素
li[:-5:-3] == [16,9] # 翻转整个列表,取-5-(-len(li))=4位元素,再按3间隔过滤
# 切片的步长不可以为0
li[::0]  # 报错(ValueError: slice step cannot be zero)
复制代码

像 C/C++、Java 和 JavaScript 等语言,虽然也支持某些“切片”功能,例如截取数组或字符串的片段,但是,它们并没有一种在语法层面上的通用性支持。

根据维基百科资料,Fortran 是最早支持切片语法的语言(1966),而 Python 则是最具代表性的语言之一。

1d0abfd2da180650ebbdf4e246d8069.png

另外,像 Perl、Ruby、Go 和 Rust 等语言,虽然也有切片,但都不及 Python 那样灵活和自由(因为它支持 step、负数索引、缺省索引)。

771ed84f31003bc03688cd36429a005.png

切片的基本用法就能够满足大部分的需求,但是,Python 切片还有一些进阶的用法,例如:切片占位符用法(可实现列表的赋值、删除与拼接操作)、自定义对象实现切片功能、迭代器切片(itertools.islice())、文件对象切片等等。关联阅读:Python进阶:全面解读高级特性之切片!

关于切片的介绍与温习,就到这里了。

下面进入文章标题的问题:Python 的切片语法为什么不会出现索引越界呢?

当我们根据单个索引进行取值时,如果索引越界,就会得到报错:“IndexError: list index out of range”。

>>> li = [1, 2]
>>> li[5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
复制代码

对于一个非空的序列对象,假设其长度为 length,则它有效的索引值是从 0 到(length - 1)。如果把负数索引也考虑进去,则单个索引值的有效区间是 [-length, length - 1] 闭区间。

但是,当 Python 切片中的索引超出这个范围时,程序并不会报错。

>>> li = [1, 2]
>>> li[1:5]  # 右索引超出
[2]
>>> li[5:6]  # 左右索引都超出
[]
复制代码

其实,对于这种现象,官方文档中有所介绍:

The slice of s from i to j is defined as the sequence of items with index k such that i <= k < j. If i or j is greater than len(s), use len(s). If i is omitted or None, use 0. If j is omitted or None, use len(s). If i is greater than or equal to j, the slice is empty.

也就是说:

  • 当左或右索引值大于序列的长度值时,就用长度值作为该索引值;
  • 当左索引值缺省或者为 None 时,就用 0 作为左索引值;
  • 当右索引值缺省或者为 None 时,就用序列长度值作为右索引值;
  • 当左索引值大于等于右索引值时,切片结果为空对象。

对照上面的例子,可以得到:

>>> li = [1, 2]
>>> li[1:5]  # 等价于 li[1:2]
[2]
>>> li[5:6]  # 等价于 li[2:2]
[]
复制代码

归结起来一句话:Python 解释器把可能导致索引越界的操作给屏蔽了,你的写法可以很自由,但是最终的结果会被死死限制在合法的索引区间内。

对于这个现象,我其实是有点疑惑的,为什么 Python 不直接报索引越界呢,为什么要修正切片的边界值,为什么一定要返回一个值呢,即便这个值可能是个空序列?

当我们使用“li[5:6]”时,至少在字面意义上想表达的是“取出索引从 5 到 6 所对应的值”,就像是在说“取出书架上从左往右数的第 6 和 7 本书”。

如果程序是如实地遵照我们的指令的话,它就应该报错,就应该说:对不起,书架上的书不够数。

实话说,我并没有查到这方面的解释,这篇文章也不是要给大家科普 Python  在设计上有什么独到的见解。恰恰相反,这篇文章的主要目的之一是希望得到大家的回复解答。

在 Go 语言中,遇到同样的场景时,它的做法是报错“runtime error: slice bounds out of range”。

在 Rust 语言中,遇到同样的场景时,它的做法是报错“byte index 5 is out of bounds of ......”。

在其它支持切片语法的语言中,也许还有跟 Python 一样的设计。但是,我还不知道有没有(学识浅薄)……

最后,继续回到标题中的问题“Python 的切片为什么不会索引越界”。我其实想问的问题有两个:

  • 当切片语法中的索引超出边界时,为什么 Python 还能返回结果,返回结果的计算原理是什么?
  • 为什么 Python 的切片语法要允许索引超出边界呢,为什么不设计成抛出索引错误?





目录
相关文章
|
5月前
|
存储 JavaScript Java
(Python基础)新时代语言!一起学习Python吧!(四):dict字典和set类型;切片类型、列表生成式;map和reduce迭代器;filter过滤函数、sorted排序函数;lambda函数
dict字典 Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。 我们可以通过声明JS对象一样的方式声明dict
343 1
|
5月前
|
Java 数据挖掘 数据处理
(Pandas)Python做数据处理必选框架之一!(一):介绍Pandas中的两个数据结构;刨析Series:如何访问数据;数据去重、取众数、总和、标准差、方差、平均值等;判断缺失值、获取索引...
Pandas 是一个开源的数据分析和数据处理库,它是基于 Python 编程语言的。 Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据(类似于Excel表格)。 Pandas 是数据科学和分析领域中常用的工具之一,它使得用户能够轻松地从各种数据源中导入数据,并对数据进行高效的操作和分析。 Pandas 主要引入了两种新的数据结构:Series 和 DataFrame。
593 0
|
5月前
|
Java 数据处理 索引
(numpy)Python做数据处理必备框架!(二):ndarray切片的使用与运算;常见的ndarray函数:平方根、正余弦、自然对数、指数、幂等运算;统计函数:方差、均值、极差;比较函数...
ndarray切片 索引从0开始 索引/切片类型 描述/用法 基本索引 通过整数索引直接访问元素。 行/列切片 使用冒号:切片语法选择行或列的子集 连续切片 从起始索引到结束索引按步长切片 使用slice函数 通过slice(start,stop,strp)定义切片规则 布尔索引 通过布尔条件筛选满足条件的元素。支持逻辑运算符 &、|。
294 0
|
5月前
|
索引 Python
Python 列表切片赋值教程:掌握 “移花接木” 式列表修改技巧
本文通过生动的“嫁接”比喻,讲解Python列表切片赋值操作。切片可修改原列表内容,实现头部、尾部或中间元素替换,支持不等长赋值,灵活实现列表结构更新。
232 1
|
5月前
|
索引 Python
098-python列表_切片_slice_开始_结束
本文介绍了Python中列表的切片(slice)操作,通过“前闭后开”原则截取列表片段,支持正负索引、省略端点等用法,并结合生活实例(如切面包、直播切片)帮助理解。切片不改变原列表,返回新列表。
347 4
|
8月前
|
存储 监控 算法
基于 Python 跳表算法的局域网网络监控软件动态数据索引优化策略研究
局域网网络监控软件需高效处理终端行为数据,跳表作为一种基于概率平衡的动态数据结构,具备高效的插入、删除与查询性能(平均时间复杂度为O(log n)),适用于高频数据写入和随机查询场景。本文深入解析跳表原理,探讨其在局域网监控中的适配性,并提供基于Python的完整实现方案,优化终端会话管理,提升系统响应性能。
216 4
|
7月前
|
数据采集 索引 Python
Python Slice函数使用教程 - 详解与示例 | Python切片操作指南
Python中的`slice()`函数用于创建切片对象,以便对序列(如列表、字符串、元组)进行高效切片操作。它支持指定起始索引、结束索引和步长,提升代码可读性和灵活性。
|
11月前
|
人工智能 索引 Python
[oeasy]python091_列表_索引_index_中括号_索引函数
本文介绍了Python中列表与字符串的索引及index函数用法。通过range生成列表,使用索引[]访问和修改列表元素,index函数查找元素位置。字符串支持索引访问但不可直接修改。还探讨了16进制数在Python中的表示方法,以及日期、月份等特殊字符的Unicode范围。最后总结了列表与字符串操作的区别,并预告后续内容,提供蓝桥云课、GitHub和Gitee链接供进一步学习。
274 20
|
索引 Python
Python 高级编程:深入探索字符串切片
在Python中,字符串切片功能强大,可灵活提取特定部分。本文详细介绍切片技巧:基本切片、省略起始或结束索引、使用负数索引、设定步长及反转字符串等。此外,还介绍了如何结合其他操作进行切片处理,如先转换大小写再提取子串。 来源:https://www.wodianping.com/yeyou/2024-10/48238.html
374 4

推荐镜像

更多