Python的切片表示法是如何工作的?也就是说:当我编写[x:y:z]、a[:]、a]::2]等代码时,我如何理解哪些元素最终会出现在切片中?请在适当的地方附上参考资料。
另请参见:为什么切片和范围上限是互斥的?
Python的切片表示法是如何工作的?也就是说:当我编写[x:y:z]、a[:]、a]::2]等代码时,我如何理解哪些元素最终会出现在切片中?请在适当的地方附上参考资料。
另请参见:为什么切片和范围上限是互斥的?
当前回答
您可以使用切片语法返回字符序列。
指定用冒号分隔的开始和结束索引,以返回字符串的一部分。
例子:
获取从位置2到位置5的字符(不包括):
b = "Hello, World!"
print(b[2:5])
从开始切片
通过省略起始索引,范围将从第一个字符开始:
例子:
获取从开始到位置5的字符(不包括):
b = "Hello, World!"
print(b[:5])
切片到底
通过省略结束索引,范围将结束:
例子:
从位置2获取字符,一直到结尾:
b = "Hello, World!"
print(b[2:])
负索引
使用负索引从字符串末尾开始切片:实例
获取字符:
来自:“世界!”中的“o”(位置-5)
至,但不包括:“世界!”中的“d”(位置-2):
b = "Hello, World!"
print(b[-5:-2])
其他回答
关于序列的索引,需要记住的重要思想是
非负指数从序列中的第一项开始;负索引从序列的最后一项开始(因此仅适用于有限序列)。
换言之,负索引右移序列长度:
0 1 2 3 4 5 6 7 ...
-------------------------
| a | b | c | d | e | f |
-------------------------
... -8 -7 -6 -5 -4 -3 -2 -1
考虑到这一点,订阅和切片很简单。
订阅
订阅使用以下语法:*
sequence[index]
订阅在索引处选择序列中的单个项目:
>>> 'abcdef'[0]
'a'
>>> 'abcdef'[-6]
'a'
订阅引发超出范围的索引的IndexError:
>>> 'abcdef'[100]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
切片
切片使用以下语法:**
sequence[start:stop:step]
切片选择序列中的一系列项目,从包含开始到不包含结束:
>>> 'abcdef'[0:2:1]
'ab'
>>> 'abcdef'[0:-4:1]
'ab'
>>> 'abcdef'[-6:-4:1]
'ab'
>>> 'abcdef'[-6:2:1]
'ab'
>>> 'abcdef'[1:-7:-1]
'ba'
>>> 'abcdef'[-5:-7:-1]
'ba'
切片默认为序列中最完整的项目范围,因此它对省略或等于“无”的任何开始、停止或步骤使用以下默认值:***
步骤默认为1;如果步骤为正start默认为0(第一项索引),stop默认为start+len(序列)(最后一项索引加一);如果步骤为负start默认为-1(最后一项索引),stop默认为start-len(序列)(第一项索引减一)。
>>> 'abcdef'[0:6:1]
'abcdef'
>>> 'abcdef'[::]
'abcdef'
>>> 'abcdef'[-1:-7:-1]
'fedcba'
>>> 'abcdef'[::-1]
'fedcba'
切片为等于零的步骤引发ValueError:
>>> 'abcdef'[::0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: slice step cannot be zero
切片不会为超出范围的开始或停止引发IndexError(与订阅相反):
>>> 'abcdef'[-100:100]
'abcdef'
*表达式sequence[index]和sequence__getitem_(索引)是等效的。
**表达式sequence[start:stop:step]、sequence[Sslice(start,stop,step)]和sequence__getitem_(slice(start,stop,step))是等效的,其中内置类slice实例包start,stop和step。
***表达式sequence[:]、sequence[::]和sequence[None:None:None]使用start、stop和step的默认值。
我想加一个你好,世界!为初学者解释切片基础知识的示例。这对我帮助很大。
让我们列出六个值[“P”、“Y”、“T”、“H”、“O”、“N”]:
+---+---+---+---+---+---+
| P | Y | T | H | O | N |
+---+---+---+---+---+---+
0 1 2 3 4 5
现在,该列表中最简单的部分是其子列表。符号是[<index>:<index>],关键是这样读:
[ start cutting before this index : end cutting before this index ]
现在,如果你从上面的列表中选择一个片段[2:5],就会发生这种情况:
| |
+---+---|---+---+---|---+
| P | Y | T | H | O | N |
+---+---|---+---+---|---+
0 1 | 2 3 4 | 5
在索引为2的元素之前进行了一次切割,在索引为5的元素之前又进行了一个切割。因此,结果将是这两个剪辑之间的一个片段,一个列表['T','H','O']。
我有点沮丧,因为找不到一个准确描述切片功能的在线源代码或Python文档。
我接受了Aaron Hall的建议,阅读了CPython源代码的相关部分,并编写了一些Python代码,这些代码执行切片与CPython中的切片类似。我已经用Python 3对整数列表进行了数百万次随机测试。
您可能会发现我的代码中对CPython中相关函数的引用很有用。
def slicer(x, start=None, stop=None, step=None):
""" Return the result of slicing list x.
See the part of list_subscript() in listobject.c that pertains
to when the indexing item is a PySliceObject.
"""
# Handle slicing index values of None, and a step value of 0.
# See PySlice_Unpack() in sliceobject.c, which
# extracts start, stop, step from a PySliceObject.
maxint = 10000000 # A hack to simulate PY_SSIZE_T_MAX
if step is None:
step = 1
elif step == 0:
raise ValueError('slice step cannot be zero')
if start is None:
start = maxint if step < 0 else 0
if stop is None:
stop = -maxint if step < 0 else maxint
# Handle negative slice indexes and bad slice indexes.
# Compute number of elements in the slice as slice_length.
# See PySlice_AdjustIndices() in sliceobject.c
length = len(x)
slice_length = 0
if start < 0:
start += length
if start < 0:
start = -1 if step < 0 else 0
elif start >= length:
start = length - 1 if step < 0 else length
if stop < 0:
stop += length
if stop < 0:
stop = -1 if step < 0 else 0
elif stop > length:
stop = length - 1 if step < 0 else length
if step < 0:
if stop < start:
slice_length = (start - stop - 1) // (-step) + 1
else:
if start < stop:
slice_length = (stop - start - 1) // step + 1
# Cases of step = 1 and step != 1 are treated separately
if slice_length <= 0:
return []
elif step == 1:
# See list_slice() in listobject.c
result = []
for i in range(stop - start):
result.append(x[i+start])
return result
else:
result = []
cur = start
for i in range(slice_length):
result.append(x[cur])
cur += step
return result
我发现更容易记住它是如何工作的,然后我可以找出任何特定的开始/停止/步骤组合。
首先了解range()是很有启发性的:
def range(start=0, stop, step=1): # Illegal syntax, but that's the effect
i = start
while (i < stop if step > 0 else i > stop):
yield i
i += step
从起点开始,一步一步递增,不要到达终点。非常简单。
关于消极步骤,需要记住的一点是,停止总是被排除的终点,无论它是高还是低。如果您希望相同的切片以相反的顺序进行,则单独进行反转会更为简单:例如,“abcde”[1:-2][::-1]从左侧切下一个字符,从右侧切下两个字符,然后反转。(另请参见reversed()。)
序列切片是相同的,只是它首先规范了负索引,并且它永远不能超出序列:
TODO:当abs(step)>1时,下面的代码出现了一个错误:“从不超出序列”;我认为我修补了它是正确的,但很难理解。
def this_is_how_slicing_works(seq, start=None, stop=None, step=1):
if start is None:
start = (0 if step > 0 else len(seq)-1)
elif start < 0:
start += len(seq)
if not 0 <= start < len(seq): # clip if still outside bounds
start = (0 if step > 0 else len(seq)-1)
if stop is None:
stop = (len(seq) if step > 0 else -1) # really -1, not last element
elif stop < 0:
stop += len(seq)
for i in range(start, stop, step):
if 0 <= i < len(seq):
yield seq[i]
不要担心“无”的细节——只需记住,省略开始和/或停止总是正确的做法,以提供整个序列。
首先规范化负索引允许开始和/或停止从结尾独立计数:'abcde'[1:-2]=='abcde'[1:3]=='bc',尽管范围(1,-2)==[]。标准化有时被认为是“对长度取模”,但注意它只增加了一次长度:例如,“abcde”[-53:42]只是整个字符串。
如果我们可以将切片与范围联系起来,这很容易理解,因为范围给出了索引。我们可以将切片分为以下两类:
1.无台阶或台阶>0。例如,[i:j]或[i:j:k](k>0)
假设序列为s=[1,2,3,4,5]。
如果0<i<len(s)和0<j<len,则[i:j:k]->范围(i,j,k)
例如,[0:3:2]->范围(0,3,2)->0,2
如果i>len或j>len,则i=len或j=len
例如,[0:100:2]->范围(0,len(s),2)->范围(0,5,2)->0,2,4
如果i<0或j<0,则i=max(0,len(s)+i)或j=max
例如,[0:-3:2]->范围(0,len(s)-3,2)->范围(0,2,2)->0
例如,[0:-1:2]->范围(0,len(s)-1,2)->范围(0,4,2)->0,2
如果未指定i,则i=0
例如,[:4:2]->范围(0,4,2)->范围(4,2)->0,2
如果未指定j,则j=len(s)
例如,[0::2]->范围(0,len(s),2)->范围(0,5,2)->0,2,4
2.步骤<0。例如,[i:j:k](k<0)
假设序列为s=[1,2,3,4,5]。
如果0<i<len(s)和0<j<len,则[i:j:k]->范围(i,j,k)
例如,[5:0:-2]->范围(5,0,-2)->5,3,1
如果i>len或j>len,则i=len(s)-1或j=len(s)-1
例如,[100:0:-2]->范围(len(s)-1,0,-2)->范围(4,0,-2)->4,2
如果i<0或j<0,则i=max(-1,len(s)+i)或j=max(-1len(s)+j)
例如,[-2:-10:-2]->range(len(s)-2,-1,-2)->range(3,-1,-1)->3,1
如果未指定i,则i=len(s)-1
例如,[:0:-2]->范围(len(s)-1,0,-2)->范围(4,0,-2)->4,2
如果未指定j,则j=-1
例如,[2::-2]->范围(2,-1,-2)->2,0
例如,[::-1]->range(len(s)-1,-1,-1)->range(4,-1,1)->4,3,2,1,0
总而言之