Python的切片表示法是如何工作的?也就是说:当我编写[x:y:z]、a[:]、a]::2]等代码时,我如何理解哪些元素最终会出现在切片中?请在适当的地方附上参考资料。
另请参见:为什么切片和范围上限是互斥的?
Python的切片表示法是如何工作的?也就是说:当我编写[x:y:z]、a[:]、a]::2]等代码时,我如何理解哪些元素最终会出现在切片中?请在适当的地方附上参考资料。
另请参见:为什么切片和范围上限是互斥的?
当前回答
以下是字符串索引的示例:
+---+---+---+---+---+
| H | e | l | p | A |
+---+---+---+---+---+
0 1 2 3 4 5
-5 -4 -3 -2 -1
str="Name string"
切片示例:[开始:结束:步骤]
str[start:end] # Items start through end-1
str[start:] # Items start through the rest of the array
str[:end] # Items from the beginning through end-1
str[:] # A copy of the whole array
以下是示例用法:
print str[0] = N
print str[0:2] = Na
print str[0:7] = Name st
print str[0:7:2] = Nm t
print str[0:-1:2] = Nm ti
其他回答
使用一点后,我意识到最简单的描述是它与for循环中的参数完全相同。。。
(from:to:step)
其中任何一项都是可选的:
(:to:step)
(from::step)
(from:to)
然后,负索引只需要将字符串的长度添加到负索引中即可理解它。
不管怎样,这对我来说都很有效。。。
枚举序列x语法允许的可能性:
>>> x[:] # [x[0], x[1], ..., x[-1] ]
>>> x[low:] # [x[low], x[low+1], ..., x[-1] ]
>>> x[:high] # [x[0], x[1], ..., x[high-1]]
>>> x[low:high] # [x[low], x[low+1], ..., x[high-1]]
>>> x[::stride] # [x[0], x[stride], ..., x[-1] ]
>>> x[low::stride] # [x[low], x[low+stride], ..., x[-1] ]
>>> x[:high:stride] # [x[0], x[stride], ..., x[high-1]]
>>> x[low:high:stride] # [x[low], x[low+stride], ..., x[high-1]]
当然,如果(高低)%步幅!=0,则终点将略低于高1。
如果步幅为负,则由于我们正在倒计时,顺序会有点改变:
>>> x[::-stride] # [x[-1], x[-1-stride], ..., x[0] ]
>>> x[high::-stride] # [x[high], x[high-stride], ..., x[0] ]
>>> x[:low:-stride] # [x[-1], x[-1-stride], ..., x[low+1]]
>>> x[high:low:-stride] # [x[high], x[high-stride], ..., x[low+1]]
扩展切片(带逗号和省略号)通常仅用于特殊数据结构(如NumPy);基本序列不支持它们。
>>> class slicee:
... def __getitem__(self, item):
... return repr(item)
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
当我第一次看到切片语法时,有一些事情不是很明显:
>>> x = [1,2,3,4,5,6]
>>> x[::-1]
[6,5,4,3,2,1]
反转顺序的简单方法!
如果出于某种原因,您希望以相反的顺序进行每一项:
>>> x = [1,2,3,4,5,6]
>>> x[::-2]
[6,4,2]
我的大脑似乎很乐意接受lst[开始:结束]包含开始项。我甚至可以说这是一个“自然的假设”。
但偶尔会有一种怀疑悄悄出现,我的大脑会要求我保证它不包含结尾元素。
在这些时刻,我依靠这个简单的定理:
for any n, lst = lst[:n] + lst[n:]
这个漂亮的属性告诉我,lst[start:end]不包含end-th项,因为它位于lst[end:]中。
注意,这个定理对任何n都是正确的。例如,您可以检查
lst = range(10)
lst[:-42] + lst[-42:] == lst
返回True。
这是我教新手切片的方法:
理解索引和切片之间的区别:
WikiPython有一幅惊人的图片,它清楚地区分了索引和切片。
这是一个包含六个元素的列表。为了更好地理解切片,请将该列表视为一组放在一起的六个框。每个盒子里都有一个字母表。
索引就像处理盒子的内容。您可以检查任何框的内容。但是你不能同时检查多个盒子的内容。你甚至可以替换盒子里的东西。但你不能在一个盒子里放两个球,也不能一次换两个球。
In [122]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']
In [123]: alpha
Out[123]: ['a', 'b', 'c', 'd', 'e', 'f']
In [124]: alpha[0]
Out[124]: 'a'
In [127]: alpha[0] = 'A'
In [128]: alpha
Out[128]: ['A', 'b', 'c', 'd', 'e', 'f']
In [129]: alpha[0,1]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-129-c7eb16585371> in <module>()
----> 1 alpha[0,1]
TypeError: list indices must be integers, not tuple
切片就像处理盒子一样。你可以拿起第一个盒子放在另一张桌子上。要拿起盒子,你只需要知道盒子的开始和结束位置。
您甚至可以选择前三个框或最后两个框,或1到4之间的所有框。所以,如果你知道开始和结束,你可以选择任何一组框。这些位置称为开始和停止位置。
有趣的是,您可以同时替换多个框。此外,您可以在任何地方放置多个盒子。
In [130]: alpha[0:1]
Out[130]: ['A']
In [131]: alpha[0:1] = 'a'
In [132]: alpha
Out[132]: ['a', 'b', 'c', 'd', 'e', 'f']
In [133]: alpha[0:2] = ['A', 'B']
In [134]: alpha
Out[134]: ['A', 'B', 'c', 'd', 'e', 'f']
In [135]: alpha[2:2] = ['x', 'xx']
In [136]: alpha
Out[136]: ['A', 'B', 'x', 'xx', 'c', 'd', 'e', 'f']
切片步骤:
到目前为止,您已连续拾取箱子。但有时你需要单独拾取。例如,您可以每隔一秒钟拾取一个盒子。你甚至可以从最后每隔三个盒子取一个。该值称为步长。这代表了您连续拾取之间的差距。如果您从开始到结束拾取框,则步长应为正值,反之亦然。
In [137]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']
In [142]: alpha[1:5:2]
Out[142]: ['b', 'd']
In [143]: alpha[-1:-5:-2]
Out[143]: ['f', 'd']
In [144]: alpha[1:5:-2]
Out[144]: []
In [145]: alpha[-1:-5:2]
Out[145]: []
Python如何找出缺少的参数:
切片时,如果忽略了任何参数,Python会尝试自动计算。
如果您检查CPython的源代码,您会发现一个名为PySlice_GetIndices Ex()的函数,它计算出任何给定参数的切片索引。下面是Python中的逻辑等价代码。
此函数采用Python对象和可选参数进行切片,并返回所请求切片的开始、停止、步骤和切片长度。
def py_slice_get_indices_ex(obj, start=None, stop=None, step=None):
length = len(obj)
if step is None:
step = 1
if step == 0:
raise Exception("Step cannot be zero.")
if start is None:
start = 0 if step > 0 else length - 1
else:
if start < 0:
start += length
if start < 0:
start = 0 if step > 0 else -1
if start >= length:
start = length if step > 0 else length - 1
if stop is None:
stop = length if step > 0 else -1
else:
if stop < 0:
stop += length
if stop < 0:
stop = 0 if step > 0 else -1
if stop >= length:
stop = length if step > 0 else length - 1
if (step < 0 and stop >= start) or (step > 0 and start >= stop):
slice_length = 0
elif step < 0:
slice_length = (stop - start + 1)/(step) + 1
else:
slice_length = (stop - start - 1)/(step) + 1
return (start, stop, step, slice_length)
这就是切片背后的智慧。由于Python有一个名为slice的内置函数,您可以传递一些参数,并检查它如何巧妙地计算缺少的参数。
In [21]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']
In [22]: s = slice(None, None, None)
In [23]: s
Out[23]: slice(None, None, None)
In [24]: s.indices(len(alpha))
Out[24]: (0, 6, 1)
In [25]: range(*s.indices(len(alpha)))
Out[25]: [0, 1, 2, 3, 4, 5]
In [26]: s = slice(None, None, -1)
In [27]: range(*s.indices(len(alpha)))
Out[27]: [5, 4, 3, 2, 1, 0]
In [28]: s = slice(None, 3, -1)
In [29]: range(*s.indices(len(alpha)))
Out[29]: [5, 4]
注:这篇文章最初写在我的博客《Python切片背后的智能》中。