为什么Python允许序列使用超出范围的切片索引?
所以我遇到了一个在我看来很奇怪的Python特性,并希望对此进行一些澄清 以下数组操作有些道理:为什么Python允许序列使用超出范围的切片索引?,python,python-3.x,sequence,slice,range-checking,Python,Python 3.x,Sequence,Slice,Range Checking,所以我遇到了一个在我看来很奇怪的Python特性,并希望对此进行一些澄清 以下数组操作有些道理: p = [1,2,3] p[3:] = [4] p = [1,2,3,4] 我想它实际上只是将这个值附加到末尾,对吗? 但是,为什么我可以这样做 p[20:22] = [5,6] p = [1,2,3,4,5,6] 更重要的是: p[20:100] = [7,8] p = [1,2,3,4,5,6,7,8] 这似乎是错误的逻辑。看起来这应该是一个错误 有什么解释吗? -这只是Python做的
p = [1,2,3]
p[3:] = [4]
p = [1,2,3,4]
我想它实际上只是将这个值附加到末尾,对吗?但是,为什么我可以这样做
p[20:22] = [5,6]
p = [1,2,3,4,5,6]
更重要的是:
p[20:100] = [7,8]
p = [1,2,3,4,5,6,7,8]
这似乎是错误的逻辑。看起来这应该是一个错误
有什么解释吗?-这只是Python做的一件奇怪的事情吗?
-它有目的吗?
-还是我的想法不对?答案如下:
s[i:j]
:从i
到j
的s
切片(注(4))
(4) 从i
到j
的s
片段被定义为项目序列
索引k
使i成为关于超出范围索引的问题的一部分
切片逻辑自动将索引剪辑到序列的长度
为了方便起见,允许切片索引延伸超过端点。必须对每个表达式进行范围检查,然后手动调整限制,这将是一件痛苦的事情,因此Python会为您这样做
考虑希望显示的文本消息不超过前50个字符的用例
简单的方法(Python现在所做的):
或者艰难的方式(自己做限额检查):
手动实现调整终点的逻辑很容易忘记,很容易出错(在两处更新50),冗长且缓慢。Python将该逻辑移动到其内部,使其简洁、自动、快速且正确。这就是我喜欢Python的原因之一:-)
关于作业长度与输入长度不匹配的部分问题
OP还想知道允许分配的理由,例如分配目标的长度(80)与替换数据长度(2)不同的p[20:100]=[7,8]
通过与字符串的类比,最容易看出动机。考虑,<代码>“五只小猴子”。替换(“小”,“Huungy”)< /代码>。请注意,目标“little”只有六个字母,“humongous”有九个字母。我们可以对列表执行相同的操作:
>>> s = list("five little monkeys")
>>> i = s.index('l')
>>> n = len('little')
>>> s[i : i+n ] = list("humongous")
>>> ''.join(s)
'five humongous monkeys'
这一切都归结为方便
在介绍copy()和clear()方法之前,这些方法曾经是流行的习惯用法:
s[:] = [] # clear a list
t = u[:] # copy a list
即使现在,我们在筛选时也会使用此选项来更新列表:
s[:] = [x for x in s if not math.isnan(x)] # filter-out NaN values
希望这些实际的例子能很好地解释为什么切片是这样工作的 我认为OP不是在问切片是如何工作的,他是在问设计选择背后的基本原理。@Primusa-我相信他们两个都在问。这解释了如何,这很好,因为它解释了为什么行为没有被破坏。“为什么”可能隐藏在某个邮件列表的深处。答案很好,但这并不能解释为什么新的数字会被附加到列表的末尾。@为了完整性,Atirag我添加了一个关于它的小广告。@Atirag索引与切片非常不同;索引总是引用值。“即使现在,我们在筛选[例如使用s[:]
]时也使用它来更新列表”-您能否详细说明为什么要在那里使用s[:]=
,而不是只使用s=
?我从未见过有人在一行的上下文中使用s[:]=
,比如你在那里写的内容。否则答案很好@Quuxplusone:Slice赋值使s
已经引用的列表发生变异;使用s=
重新绑定s
以引用新列表。如果列表可以通过多个名称访问,并且您希望所有名称都能看到该变异,那么切片分配就是您想要的。另外,如果s
是全局的,则重新分配s
将需要一个global
声明,但即使没有global
语句,切片分配也会有类似的效果。在其他语言中,我总是到处写这种东西:if I>sequence.length():return sequence.slice(0,sequence.length())else sequence.slice(0,n)
这与在Python中仅使用sequence[:n]
完全相同。它为您节省了一条if语句和对length
.BTW的两个调用。您可以将切片视为“集”。因此p[20:22]
是索引介于20和22之间的所有元素的序列。空集是有效集。这与说p[20]不同
它断言存在索引为20的元素。因此,查找元素和片段之间的范围检查差异反映了两种不同的含义。我认为这是一个更广泛的问题,即为什么Python允许在不同长度的序列片段中添加序列,以及它的好处是什么。另一个问题是estion根本没有解决这个问题的赋值部分,它只是讨论了切片。
>>> s = list("five little monkeys")
>>> i = s.index('l')
>>> n = len('little')
>>> s[i : i+n ] = list("humongous")
>>> ''.join(s)
'five humongous monkeys'
s[:] = [] # clear a list
t = u[:] # copy a list
s[:] = [x for x in s if not math.isnan(x)] # filter-out NaN values