Python 中的切片工作原理
- 2024-11-15 08:37:00
- admin 原创
- 18
问题描述:
Python 的切片符号如何工作?也就是说:当我编写诸如、a[x:y:z]
等代码时,如何了解哪些元素最终进入切片?a[:]
`a[::2]`
请参阅为什么切片和范围的上限互斥?以了解为什么xs[0:2] == [xs[0], xs[1]]
而不是 [..., xs[2]]
。
请参阅创建一个包含原始列表中每 N 个项目的新列表。xs[::N]
请参阅如何使用列表切片进行赋值?以了解其作用。
xs[0:2] = ["a", "b"]
解决方案 1:
语法是:
a[start:stop] # items start through stop-1
a[start:] # items start through the rest of the array
a[:stop] # items from the beginning through stop-1
a[:] # a copy of the whole array
还有step
可与上述任何一个一起使用的值:
a[start:stop:step] # start through not past stop, by step
要记住的关键点是,该值表示不在:stop
所选切片中的第一个值。因此,和之间的差值是所选元素的数量(如果为 1,则为默认值)。stop
`start`step
另一个特点是start
或stop
可以是负数,这意味着它从数组的末尾而不是开头计数。所以:
a[-1] # last item in the array
a[-2:] # last two items in the array
a[:-2] # everything except the last two items
类似地,step
也可能是负数:
a[::-1] # all items in the array, reversed
a[1::-1] # the first two items, reversed
a[:-3:-1] # the last two items, reversed
a[-3::-1] # everything except the last two items, reversed
如果项目数少于您要求的数,Python 对程序员来说很友善。例如,如果您要求a[:-2]
且a
仅包含一个元素,您将得到一个空列表而不是错误。有时您更希望出现错误,因此您必须意识到这种情况可能会发生。
slice
与对象的关系
一个slice
对象可以表示一个切片操作,即:
a[start:stop:step]
相当于:
a[slice(start, stop, step)]
Slice 对象的行为也根据参数数量略有不同,类似于range()
,即同时支持slice(stop)
和slice(start, stop[, step])
。要跳过指定给定参数,可以使用None
,这样例如a[start:]
等同于a[slice(start, None)]
或a[::-1]
等同于a[slice(None, None, -1)]
。
虽然:
基于的符号对于简单切片非常有用,但slice()
对象的明确使用简化了程序化切片的生成。
解决方案 2:
Python 教程对此进行了讨论(向下滚动一点,直到到达有关切片的部分)。
教程中的 ASCII 艺术图表有助于记住切片的工作原理:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
记住切片如何工作的一种方法是将索引视为指向字符之间,其中第一个字符的左边缘编号为 0。然后, n 个字符的字符串的最后一个字符的右边缘的索引为n。
解决方案 3:
枚举语法允许的序列的可能性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]]
当然,如果(high-low)%stride != 0
,那么终点就会比 低一点high-1
。
如果stride
为负数,则由于我们正在倒数,所以顺序会稍有改变:
>>> 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)'
解决方案 4:
上面的答案没有讨论切片分配。要理解切片分配,在 ASCII 艺术中添加另一个概念会很有帮助:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
Slice position: 0 1 2 3 4 5 6
Index position: 0 1 2 3 4 5
>>> p = ['P','y','t','h','o','n']
# Why the two sets of numbers:
# indexing gives items, not lists
>>> p[0]
'P'
>>> p[5]
'n'
# Slicing gives lists
>>> p[0:1]
['P']
>>> p[0:2]
['P','y']
一种启发式方法是,对于从零到 n 的切片,思考:“零是开始,从头开始并取列表中的 n 个项目”。
>>> p[5] # the last of six items, indexed from zero
'n'
>>> p[0:5] # does NOT include the last item!
['P','y','t','h','o']
>>> p[0:6] # not p[0:5]!!!
['P','y','t','h','o','n']
另一个启发式方法是,“对于任何切片,将开头替换为零,应用前一个启发式方法获取列表的末尾,然后重新计算第一个数字以从开头切掉项目”
>>> p[0:4] # Start at the beginning and count out 4 items
['P','y','t','h']
>>> p[1:4] # Take one item off the front
['y','t','h']
>>> p[2:4] # Take two items off the front
['t','h']
# etc.
切片分配的第一条规则是,由于切片返回一个列表,因此切片分配需要一个列表(或其他可迭代对象):
>>> p[2:3]
['t']
>>> p[2:3] = ['T']
>>> p
['P','y','T','h','o','n']
>>> p[2:3] = 't'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only assign an iterable
切片分配的第二条规则(您也可以在上面看到)是,切片索引返回列表的任何部分,都是通过切片分配更改的相同部分:
>>> p[2:4]
['T','h']
>>> p[2:4] = ['t','r']
>>> p
['P','y','t','r','o','n']
切片分配的第三条规则是,分配的列表(可迭代)不必具有相同的长度;索引切片只是被切出来并被分配的内容整体替换:
>>> p = ['P','y','t','h','o','n'] # Start over
>>> p[2:4] = ['s','p','a','m']
>>> p
['P','y','s','p','a','m','o','n']
最难适应的部分是分配给空切片。使用启发式 1 和 2,很容易理解索引空切片:
>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
['P','y','t','h']
>>> p[1:4]
['y','t','h']
>>> p[2:4]
['t','h']
>>> p[3:4]
['h']
>>> p[4:4]
[]
然后,一旦你看到了这一点,对空切片的切片分配也是有意义的:
>>> p = ['P','y','t','h','o','n']
>>> p[2:4] = ['x','y'] # Assigned list is same length as slice
>>> p
['P','y','x','y','o','n'] # Result is same length
>>> p = ['P','y','t','h','o','n']
>>> p[3:4] = ['x','y'] # Assigned list is longer than slice
>>> p
['P','y','t','x','y','o','n'] # The result is longer
>>> p = ['P','y','t','h','o','n']
>>> p[4:4] = ['x','y']
>>> p
['P','y','t','h','x','y','o','n'] # The result is longer still
请注意,由于我们没有更改切片的第二个数字 (4),因此插入的项目始终紧靠“o”堆叠,即使我们分配给空切片也是如此。因此,空切片分配的位置是非空切片分配位置的逻辑扩展。
稍微回顾一下,当您继续按照我们的流程计算切片的开头时,会发生什么?
>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
['P','y','t','h']
>>> p[1:4]
['y','t','h']
>>> p[2:4]
['t','h']
>>> p[3:4]
['h']
>>> p[4:4]
[]
>>> p[5:4]
[]
>>> p[6:4]
[]
使用切片后,一旦完成,就完成了;它不会开始向后切片。在 Python 中,除非您使用负数明确要求,否则不会获得负步幅。
>>> p[5:3:-1]
['n','o']
“一旦完成,就完成了”规则有一些奇怪的后果:
>>> p[4:4]
[]
>>> p[5:4]
[]
>>> p[6:4]
[]
>>> p[6]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
事实上,与索引相比,Python 切片具有奇怪的防错功能:
>>> p[100:200]
[]
>>> p[int(2e99):int(1e99)]
[]
这有时会很有用,但也可能导致一些奇怪的行为:
>>> p
['P', 'y', 't', 'h', 'o', 'n']
>>> p[int(2e99):int(1e99)] = ['p','o','w','e','r']
>>> p
['P', 'y', 't', 'h', 'o', 'n', 'p', 'o', 'w', 'e', 'r']
根据您的应用程序,这可能是...也可能不是...您所希望的!
以下是我原来的回答。它对很多人都有用,所以我不想删除它。
>>> r=[1,2,3,4]
>>> r[1:1]
[]
>>> r[1:1]=[9,8]
>>> r
[1, 9, 8, 2, 3, 4]
>>> r[1:1]=['blah']
>>> r
[1, 'blah', 9, 8, 2, 3, 4]
这也许可以阐明切片和索引之间的区别。
解决方案 5:
解释 Python 的切片符号
简而言之,:
下标符号 ( ) 中的冒号 ( subscriptable[subscriptarg]
) 构成切片符号,其具有可选参数start
、stop
和step
:
sliceable[start:stop:step]
Python 切片是一种快速计算的方法,可以有条不紊地访问数据的各个部分。在我看来,即使是中级 Python 程序员,也必须熟悉该语言的一个方面。
重要定义
首先,让我们定义几个术语:
start
:切片的起始索引,除非与stop相同,否则将包含该索引处的元素,默认为 0,即第一个索引。如果为负数,则表示n
从末尾开始。
stop
:切片的结束索引,不包括该索引处的元素,默认为被切片序列的长度,即直到末尾为止。
step
:索引增加的量,默认为 1。如果为负数,则反向对可迭代对象进行切片。
索引的工作原理
您可以创建任何正数或负数。正数的含义很简单,但对于负数,就像 Python 中的索引一样,对于开始和停止,您从末尾向后计数,对于步骤,您只需减少索引即可。此示例来自文档的教程,但我对其进行了轻微修改,以指示每个索引引用序列中的哪个项目:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5
-6 -5 -4 -3 -2 -1
切片的工作原理
要将切片符号与支持它的序列一起使用,必须在序列后面的方括号中至少包含一个冒号(根据 Python 数据模型,这实际上实现了__getitem__
序列的方法。)
切片符号的工作原理如下:
sequence[start:stop:step]
回想一下, start、stop和step都有默认值,因此要访问默认值,只需省略参数即可。
从列表(或任何其他支持它的序列,如字符串)中获取最后九个元素的切片符号如下所示:
my_list[-9:]
当我看到这个时,我将括号内的部分读作“从末尾开始第 9 个,到末尾。”(实际上,我在心里将其缩写为“-9,on”)
解释:
完整符号为
my_list[-9:None:None]
并替换默认值(实际上当step
为负数时,stop
的默认值为-len(my_list) - 1
,因此None
停止实际上只是意味着它会转到哪个结束步骤):
my_list[-9:len(my_list):1]
冒号, , 告诉 Python 你给的是切片,而不是常规索引。这就是为什么在 Python 2 中创建列表浅拷贝的惯用方法是:
list_copy = sequence[:]
清除它们的方法如下:
del my_list[:]
(Python 3 获得了list.copy
andlist.clear
方法。)
当为负数时,和的step
默认值会改变start
`stop`
默认情况下,当step
参数为空(或None
)时,它会被分配给+1
。
但是您可以传递一个负整数,并且列表(或大多数其他标准可切片)将从末尾到开头进行切片。
因此负切片将改变start
和的默认值stop
!
在来源中确认这一点
我喜欢鼓励用户阅读源代码和文档。切片对象的源代码和此逻辑可在此处找到。首先,我们确定是否step
为负数:
step_is_negative = step_sign < 0;
如果是这样,下限-1
意味着我们一直切片到开头,包括开头,上限是长度减 1,意味着我们从结尾开始。(请注意,这与用户可能在 Python 中传递表示最后一项的索引的语义不同。-1
)-1
if (step_is_negative) { lower = PyLong_FromLong(-1L); if (lower == NULL) goto error; upper = PyNumber_Add(length, lower); if (upper == NULL) goto error; }
否则step
为正数,下限为零,上限(我们达到但不包括)为切片列表的长度。
else { lower = _PyLong_Zero; Py_INCREF(lower); upper = length; Py_INCREF(upper); }
然后,我们可能需要应用start
和的默认值——当为负数stop
时,的默认值start
将计算为上限:step
if (self->start == Py_None) { start = step_is_negative ? upper : lower; Py_INCREF(start); }
以及stop
,下限:
if (self->stop == Py_None) { stop = step_is_negative ? lower : upper; Py_INCREF(stop); }
给你的切片起一个描述性的名字!
您可能会发现将切片的形成与将其传递给list.__getitem__
方法分开很有用(这就是方括号的作用)。即使您不是新手,它也能让您的代码更具可读性,以便其他可能需要阅读您的代码的人可以更容易地理解您正在做的事情。
但是,您不能直接将一些用冒号分隔的整数分配给变量。您需要使用切片对象:
last_nine_slice = slice(-9, None)
第二个参数None
是必需的,因此第一个参数被解释为参数start
,否则它将是stop
参数。
然后您可以将切片对象传递给您的序列:
>>> list(range(100))[last_nine_slice]
[91, 92, 93, 94, 95, 96, 97, 98, 99]
有趣的是范围也可以进行切片:
>>> range(100)[last_nine_slice]
range(91, 100)
内存注意事项:
由于 Python 列表的切片会在内存中创建新对象,因此需要注意的另一个重要函数是itertools.islice
。通常,您需要对切片进行迭代,而不仅仅是在内存中静态创建它。islice
非常适合这种情况。需要注意的是,它不支持 、 或 的负参数start
,stop
因此step
如果这是一个问题,您可能需要提前计算索引或反转可迭代对象。
length = 100
last_nine_iter = itertools.islice(list(range(length)), length-9, None, 1)
list_last_nine = list(last_nine_iter)
现在:
>>> list_last_nine
[91, 92, 93, 94, 95, 96, 97, 98, 99]
列表切片会生成副本,这是列表本身的特性。如果您要切片高级对象(如 Pandas DataFrame),它可能会返回原始视图,而不是副本。
解决方案 6:
当我第一次看到切片语法时,有几件事我并没有立即意识到:
>>> 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]
解决方案 7:
在 Python 2.7 中
Python 中的切片
[a:b:c]
len = length of string, tuple or list
c -- default is +1. The sign of c indicates forward or backward, absolute value of c indicates steps. Default is forward with step size 1. Positive means forward, negative means backward.
a -- When c is positive or blank, default is 0. When c is negative, default is -1.
b -- When c is positive or blank, default is len. When c is negative, default is -(len+1).
理解索引分配非常重要。
In forward direction, starts at 0 and ends at len-1
In backward direction, starts at -1 and ends at -len
当您说 [a:b:c] 时,您是在根据 c 的符号(向前或向后)表示从 a 开始到 b 结束(不包括第 b 个索引处的元素)。使用上面的索引规则,并记住您只能找到此范围内的元素:
-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1
但这个范围在两个方向上无限延伸:
...,-len -2 ,-len-1,-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1, len, len +1, len+2 , ....
例如:
0 1 2 3 4 5 6 7 8 9 10 11
a s t r i n g
-9 -8 -7 -6 -5 -4 -3 -2 -1
如果您选择的 a、b 和 c 允许与上面的范围重叠,当您使用上述 a、b、c 的规则进行遍历时,您将获得一个包含元素的列表(遍历期间触及),或者您将获得一个空列表。
最后一件事:如果 a 和 b 相等,那么您也会得到一个空列表:
>>> l1
[2, 3, 4]
>>> l1[:]
[2, 3, 4]
>>> l1[::-1] # a default is -1 , b default is -(len+1)
[4, 3, 2]
>>> l1[:-4:-1] # a default is -1
[4, 3, 2]
>>> l1[:-3:-1] # a default is -1
[4, 3]
>>> l1[::] # c default is +1, so a default is 0, b default is len
[2, 3, 4]
>>> l1[::-1] # c is -1 , so a default is -1 and b default is -(len+1)
[4, 3, 2]
>>> l1[-100:-200:-1] # Interesting
[]
>>> l1[-1:-200:-1] # Interesting
[4, 3, 2]
>>> l1[-1:-1:1]
[]
>>> l1[-1:5:1] # Interesting
[4]
>>> l1[1:-7:1]
[]
>>> l1[1:-7:-1] # Interesting
[3, 2]
>>> l1[:-2:-2] # a default is -1, stop(b) at -2 , step(c) by 2 in reverse direction
[4]
解决方案 8:
在http://wiki.python.org/moin/MovingToPythonFromOtherLanguages上找到了这张很棒的表格
Python indexes and slices for a six-element list.
Indexes enumerate the elements, slices enumerate the spaces between the elements.
Index from rear: -6 -5 -4 -3 -2 -1 a=[0,1,2,3,4,5] a[1:]==[1,2,3,4,5]
Index from front: 0 1 2 3 4 5 len(a)==6 a[:5]==[0,1,2,3,4]
+---+---+---+---+---+---+ a[0]==0 a[:-2]==[0,1,2,3]
| a | b | c | d | e | f | a[5]==5 a[1:2]==[1]
+---+---+---+---+---+---+ a[-1]==5 a[1:-1]==[1,2,3,4]
Slice from front: : 1 2 3 4 5 : a[-2]==4
Slice from rear: : -5 -4 -3 -2 -1 :
b=a[:]
b==[0,1,2,3,4,5] (shallow copy of a)
解决方案 9:
使用一段时间后,我意识到最简单的描述是它与循环中的参数完全相同for
......
(from:to:step)
其中任何一个都是可选的:
(:to:step)
(from::step)
(from:to)
然后负索引只需要你将字符串的长度添加到负索引就可以理解它。
无论如何,这对我有用......
解决方案 10:
我发现更容易记住它的工作原理,然后我可以找出任何特定的开始/停止/步骤组合。
首先了解以下内容是有益的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
从 开始start
,增加step
,不达stop
。很简单。
关于负步长要记住的是,它stop
始终是排除的一端,无论它是高端还是低端。如果您想要以相反的顺序进行相同的切片,则单独进行反转会更简洁:例如'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]
不要担心is None
细节 - 只需记住省略start
和/或stop
总是做正确的事情来给你整个序列。
首先规范化负索引允许从末尾独立计算开始和/或停止:'abcde'[1:-2] == 'abcde'[1:3] == 'bc'
尽管range(1,-2) == []
。规范化有时被认为是“对长度取模”,但请注意它只添加一次长度:例如'abcde'[-53:42]
只是整个字符串。
解决方案 11:
我自己使用“元素之间的索引点”方法来思考这个问题,但有一种描述方法有时可以帮助其他人理解,那就是:
mylist[X:Y]
X 是您想要的第一个元素的索引。 Y 是您不
想要的
第一个元素的索引。
解决方案 12:
Index:
------------>
0 1 2 3 4
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
0 -4 -3 -2 -1
<------------
Slice:
<---------------|
|--------------->
: 1 2 3 4 :
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
: -4 -3 -2 -1 :
|--------------->
<---------------|
我希望这能帮助您在 Python 中建模列表。
参考: http: //wiki.python.org/moin/MovingToPythonFromOtherLanguages
解决方案 13:
这是我向新手传授切片的方法:
了解索引和切片之间的区别:
Wiki Python 有一张令人惊叹的图片,它清楚地区分了索引和切片。
它是一个包含六个元素的列表。为了更好地理解切片,请将该列表视为一组放在一起的六个盒子。每个盒子里都有一个字母表。
索引就像处理盒子里的东西。你可以检查任何盒子里的东西。但你不能一次检查多个盒子里的东西。你甚至可以替换盒子里的东西。但你不能把两个球放在一个盒子里,也不能一次替换两个球。
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_GetIndicesEx() 的函数,它可以计算出任何给定参数的切片索引。以下是 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 有一个名为切片的内置函数,您可以传递一些参数并检查它如何智能地计算缺失的参数。
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 Slices 背后的智能》中。
解决方案 14:
Python 切片符号:
a[start:end:step]
对于
start
和end
,负值被解释为相对于序列的末尾。正索引表示要包含的最后一个元素之后的
end
位置。空白值默认如下:
[+0:-0:1]
。start
使用负面步骤会逆转和的解释end
该符号扩展到(numpy)矩阵和多维数组。例如,要切片整个列,您可以使用:
m[::,0:2:] ## slice the first two columns
切片保存的是数组元素的引用,而不是副本。如果要单独复制数组,可以使用deepcopy()
。
解决方案 15:
您还可以使用切片赋值从列表中删除一个或多个元素:
r = [1, 'blah', 9, 8, 2, 3, 4]
>>> r[1:4] = []
>>> r
[1, 2, 3, 4]
解决方案 16:
这只是一些额外的信息...请考虑下面的列表
>>> l=[12,23,345,456,67,7,945,467]
反转列表的其他一些技巧:
>>> l[len(l):-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]
>>> l[:-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]
>>> l[len(l)::-1]
[467, 945, 7, 67, 456, 345, 23, 12]
>>> l[::-1]
[467, 945, 7, 67, 456, 345, 23, 12]
>>> l[-1:-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]
解决方案 17:
切片符号
为了简单起见,记住切片只有一种形式:
s[start:end:step]
它的工作原理如下:
s
:可切片的物体start
:开始迭代的第一个索引end
:最后一个索引,注意该end
索引不会包含在结果切片中step
:选择每个step
索引的元素
另一件重要的事情是:所有start
、end
、step
都可以省略!如果省略它们,则将相应地使用它们的默认值:0
、len(s)
、1
。
因此可能的变化是:
# Mostly used variations
s[start:end]
s[start:]
s[:end]
# Step-related variations
s[:end:step]
s[start::step]
s[::step]
# Make a copy
s[:]
注意:如果start >= end
(仅考虑当step>0
) ,Python 将返回一个空切片[]
。
陷阱
以上部分解释了切片的核心功能,在大多数情况下它都能正常工作。但是,你还是应该注意一些陷阱,本部分将解释这些陷阱。
负面指标
最让 Python 学习者感到困惑的就是索引可以为负数!
不要惊慌:负索引表示向后计数。
例如:
s[-5:] # Start at the 5th index from the end of array,
# thus returning the last 5 elements.
s[:-5] # Start at index 0, and end until the 5th index from end of array,
# thus returning s[0:len(s)-5].
负面举措
让事情变得更加令人困惑的是,这step
也可能是负面的!
负数步长意味着向后迭代数组:从末尾到开始,包括末尾索引,并且从结果中排除起始索引。
注意start
:当 step 为负数时,的默认值为len(s)
(虽然end
不等于0
,因为s[::-1]
包含s[0]
)。例如:
s[::-1] # Reversed slice
s[len(s)::-1] # The same as above, reversed slice
s[0:len(s):-1] # Empty list
超出范围错误?
令人惊讶的是:当索引超出范围时,切片不会引发 IndexError!
如果索引超出范围,Python 会根据情况尽量将索引设置为0
或。例如:len(s)
s[:len(s)+5] # The same as s[:len(s)]
s[-len(s)-5::] # The same as s[0:]
s[len(s)+5::-1] # The same as s[len(s)::-1], and the same as s[::-1]
3.示例
让我们用例子来结束这个答案,解释我们所讨论的所有内容:
# Create our array for demonstration
In [1]: s = [i for i in range(10)]
In [2]: s
Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [3]: s[2:] # From index 2 to last index
Out[3]: [2, 3, 4, 5, 6, 7, 8, 9]
In [4]: s[:8] # From index 0 up to index 8
Out[4]: [0, 1, 2, 3, 4, 5, 6, 7]
In [5]: s[4:7] # From index 4 (included) up to index 7(excluded)
Out[5]: [4, 5, 6]
In [6]: s[:-2] # Up to second last index (negative index)
Out[6]: [0, 1, 2, 3, 4, 5, 6, 7]
In [7]: s[-2:] # From second last index (negative index)
Out[7]: [8, 9]
In [8]: s[::-1] # From last to first in reverse order (negative step)
Out[8]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In [9]: s[::-2] # All odd numbers in reversed order
Out[9]: [9, 7, 5, 3, 1]
In [11]: s[-2::-2] # All even numbers in reversed order
Out[11]: [8, 6, 4, 2, 0]
In [12]: s[3:15] # End is out of range, and Python will set it to len(s).
Out[12]: [3, 4, 5, 6, 7, 8, 9]
In [14]: s[5:1] # Start > end; return empty list
Out[14]: []
In [15]: s[11] # Access index 11 (greater than len(s)) will raise an IndexError
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-15-79ffc22473a3> in <module>()
----> 1 s[11]
IndexError: list index out of range
解决方案 18:
前面的答案没有讨论使用著名的NumPy包可以实现的多维数组切片:
切片也可以应用于多维数组。
# Here, a is a NumPy array
>>> a
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
>>> a[:2, 0:3:2]
array([[1, 3],
[5, 7]])
逗号前的“ :2
”作用于第一维,0:3:2
逗号后的“ ”作用于第二维。
解决方案 19:
一般来说,编写包含大量硬编码索引值的代码会导致可读性和维护混乱。例如,如果你一年后再回头看这段代码,你会想知道自己在写这段代码时在想什么。所示的解决方案只是一种更清楚地说明代码实际在做什么的方法。通常,内置的slice()会创建一个切片对象,该对象可以在允许切片的任何地方使用。例如:
>>> items = [0, 1, 2, 3, 4, 5, 6]
>>> a = slice(2, 4)
>>> items[2:4]
[2, 3]
>>> items[a]
[2, 3]
>>> items[a] = [10,11]
>>> items
[0, 1, 10, 11, 4, 5, 6]
>>> del items[a]
>>> items
[0, 1, 4, 5, 6]
如果您有一个切片实例 s,您可以通过分别查看其 s.start、s.stop 和 s.step 属性来获取有关它的更多信息。例如:
>>> a = slice(10, 50, 2) >>> a.start 10 >>> a.stop 50 >>> a.step 2 >>>
解决方案 20:
切片规则如下:
[lower bound : upper bound : step size]
I-將upper bound
和轉換lower bound
為常用符號。
II-然后检查step size
是正值还是负值。
(i)如果step size
为正值,upper bound
则应大于 lower bound
,否则empty string
打印。例如:
s="Welcome"
s1=s[0:3:1]
print(s1)
输出:
Wel
但是如果我们运行以下代码:
s="Welcome"
s1=s[3:0:1]
print(s1)
它将返回一个空字符串。
(ii)如果step size
为负值,upper bound
则应小于 lower bound
,否则empty string
将打印。例如:
s="Welcome"
s1=s[3:0:-1]
print(s1)
输出:
cle
但如果我们运行以下代码:
s="Welcome"
s1=s[0:5:-1]
print(s1)
输出将是一个空字符串。
因此在代码中:
str = 'abcd'
l = len(str)
str2 = str[l-1:0:-1] #str[3:0:-1]
print(str2)
str2 = str[l-1:-1:-1] #str[3:-1:-1]
print(str2)
在第一个中str2=str[l-1:0:-1]
,upper bound
小于,lower bound
因此打印dcb
。
但是在 中str2=str[l-1:-1:-1]
,upper bound
不小于(lower bound
转换lower bound
成负值后为-1
:因为index
的最后一个元素是 -1 和 3)。
解决方案 21:
在我看来,如果您按照以下方式看待 Python 字符串切片符号(继续阅读),您将更好地理解和记忆它。
让我们处理以下字符串...
azString = "abcdefghijklmnopqrstuvwxyz"
对于那些不知道的人,你可以azString
使用符号创建任何子字符串azString[x:y]
如果来自其他编程语言,那么常识就会受到损害。x 和 y 是什么?
我必须坐下来运行几种场景,以寻求一种记忆技巧,这将有助于我记住 x 和 y 是什么,并帮助我在第一次尝试时正确地切分字符串。
我的结论是,x 和 y 应该被视为我们想要附加的字符串周围的边界索引。因此,我们应该将表达式视为 ,azString[index1, index2]
或者更清楚地将其视为azString[index_of_first_character, index_after_the_last_character]
。
这是一个可视化示例...
Letters a b c d e f g h i j ...
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
┊ ┊
Indexes 0 1 2 3 4 5 6 7 8 9 ...
┊ ┊
cdefgh index1 index2
因此,您所要做的就是将 index1 和 index2 设置为包围所需子字符串的值。例如,要获取子字符串“cdefgh”,您可以使用azString[2:8]
,因为“c”左侧的索引为 2,而“h”右侧的大小为 8。
请记住,我们正在设置边界。这些边界是您可以放置一些括号的位置,这些括号将围绕子字符串,如下所示...
ab [ cdefgh ] ij
这个技巧一直有效并且很容易记住。
解决方案 22:
我个人认为它就像一个for
循环:
a[start:end:step]
# for(i = start; i < end; i += step)
start
另请注意,和的负值end
是相对于列表末尾的,并在上例中通过计算given_index + a.shape[0]
。
解决方案 23:
#!/usr/bin/env python
def slicegraphical(s, lista):
if len(s) > 9:
print """Enter a string of maximum 9 characters,
so the printig would looki nice"""
return 0;
# print " ",
print ' '+'+---' * len(s) +'+'
print ' ',
for letter in s:
print '| {}'.format(letter),
print '|'
print " ",; print '+---' * len(s) +'+'
print " ",
for letter in range(len(s) +1):
print '{} '.format(letter),
print ""
for letter in range(-1*(len(s)), 0):
print ' {}'.format(letter),
print ''
print ''
for triada in lista:
if len(triada) == 3:
if triada[0]==None and triada[1] == None and triada[2] == None:
# 000
print s+'[ : : ]' +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] == None and triada[1] == None and triada[2] != None:
# 001
print s+'[ : :{0:2d} ]'.format(triada[2], '','') +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] == None and triada[1] != None and triada[2] == None:
# 010
print s+'[ :{0:2d} : ]'.format(triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] == None and triada[1] != None and triada[2] != None:
# 011
print s+'[ :{0:2d} :{1:2d} ]'.format(triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] != None and triada[1] == None and triada[2] == None:
# 100
print s+'[{0:2d} : : ]'.format(triada[0]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] != None and triada[1] == None and triada[2] != None:
# 101
print s+'[{0:2d} : :{1:2d} ]'.format(triada[0], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] != None and triada[1] != None and triada[2] == None:
# 110
print s+'[{0:2d} :{1:2d} : ]'.format(triada[0], triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif triada[0] != None and triada[1] != None and triada[2] != None:
# 111
print s+'[{0:2d} :{1:2d} :{2:2d} ]'.format(triada[0], triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
elif len(triada) == 2:
if triada[0] == None and triada[1] == None:
# 00
print s+'[ : ] ' + ' = ', s[triada[0]:triada[1]]
elif triada[0] == None and triada[1] != None:
# 01
print s+'[ :{0:2d} ] '.format(triada[1]) + ' = ', s[triada[0]:triada[1]]
elif triada[0] != None and triada[1] == None:
# 10
print s+'[{0:2d} : ] '.format(triada[0]) + ' = ', s[triada[0]:triada[1]]
elif triada[0] != None and triada[1] != None:
# 11
print s+'[{0:2d} :{1:2d} ] '.format(triada[0],triada[1]) + ' = ', s[triada[0]:triada[1]]
elif len(triada) == 1:
print s+'[{0:2d} ] '.format(triada[0]) + ' = ', s[triada[0]]
if __name__ == '__main__':
# Change "s" to what ever string you like, make it 9 characters for
# better representation.
s = 'COMPUTERS'
# add to this list different lists to experement with indexes
# to represent ex. s[::], use s[None, None,None], otherwise you get an error
# for s[2:] use s[2:None]
lista = [[4,7],[2,5,2],[-5,1,-1],[4],[-4,-6,-1], [2,-3,1],[2,-3,-1], [None,None,-1],[-5,None],[-5,0,-1],[-5,None,-1],[-1,1,-2]]
slicegraphical(s, lista)
您可以运行该脚本并进行试验,下面是我从脚本中获得的一些示例。
+---+---+---+---+---+---+---+---+---+
| C | O | M | P | U | T | E | R | S |
+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6 7 8 9
-9 -8 -7 -6 -5 -4 -3 -2 -1
COMPUTERS[ 4 : 7 ] = UTE
COMPUTERS[ 2 : 5 : 2 ] = MU
COMPUTERS[-5 : 1 :-1 ] = UPM
COMPUTERS[ 4 ] = U
COMPUTERS[-4 :-6 :-1 ] = TU
COMPUTERS[ 2 :-3 : 1 ] = MPUT
COMPUTERS[ 2 :-3 :-1 ] =
COMPUTERS[ : :-1 ] = SRETUPMOC
COMPUTERS[-5 : ] = UTERS
COMPUTERS[-5 : 0 :-1 ] = UPMO
COMPUTERS[-5 : :-1 ] = UPMOC
COMPUTERS[-1 : 1 :-2 ] = SEUM
[Finished in 0.9s]
当使用负数步长时,请注意答案向右移动 1。
解决方案 24:
我的大脑似乎很乐意接受lst[start:end]
包含start
第 - 个项目的。我甚至可以说这是一个“自然假设”。
但偶尔也会有疑问出现,我的大脑会要求确认它不包含第end
- 个元素。
在这些时刻,我依靠这个简单的定理:
for any n, lst = lst[:n] + lst[n:]
这个漂亮的属性告诉我lst[start:end]
不包含end
第项,因为它在lst[end:]
。
请注意,此定理对任何情况都成立n
。例如,你可以检查
lst = range(10)
lst[:-42] + lst[-42:] == lst
返回True
。
解决方案 25:
在 Python 中,切片的最基本形式如下:
l[start:end]
其中l
是某个集合,start
是包含索引,是end
排他索引。
In [1]: l = list(range(10))
In [2]: l[:5] # First five elements
Out[2]: [0, 1, 2, 3, 4]
In [3]: l[-5:] # Last five elements
Out[3]: [5, 6, 7, 8, 9]
从开始切片时,可以省略零索引;切片到末尾时,可以省略最终索引,因为它是多余的,所以不要太冗长:
In [5]: l[:3] == l[0:3]
Out[5]: True
In [6]: l[7:] == l[7:len(l)]
Out[6]: True
当相对于集合末尾进行偏移时,负整数很有用:
In [7]: l[:-1] # Include all elements but the last one
Out[7]: [0, 1, 2, 3, 4, 5, 6, 7, 8]
In [8]: l[-3:] # Take the last three elements
Out[8]: [7, 8, 9]
切片时可以提供超出范围的索引,例如:
In [9]: l[:20] # 20 is out of index bounds, and l[20] will raise an IndexError exception
Out[9]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [11]: l[-20:] # -20 is out of index bounds, and l[-20] will raise an IndexError exception
Out[11]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
请记住,对集合进行切片的结果是一个全新的集合。此外,在分配中使用切片符号时,切片分配的长度不必相同。分配的切片之前和之后的值将保留,并且集合将缩小或增大以包含新值:
In [16]: l[2:6] = list('abc') # Assigning fewer elements than the ones contained in the sliced collection l[2:6]
In [17]: l
Out[17]: [0, 1, 'a', 'b', 'c', 6, 7, 8, 9]
In [18]: l[2:5] = list('hello') # Assigning more elements than the ones contained in the sliced collection l [2:5]
In [19]: l
Out[19]: [0, 1, 'h', 'e', 'l', 'l', 'o', 6, 7, 8, 9]
如果省略开始和结束索引,则会复制该集合:
In [14]: l_copy = l[:]
In [15]: l == l_copy and l is not l_copy
Out[15]: True
如果在执行赋值操作时省略了开始和结束索引,则集合的整个内容将被替换为所引用内容的副本:
In [20]: l[:] = list('hello...')
In [21]: l
Out[21]: ['h', 'e', 'l', 'l', 'o', '.', '.', '.']
除了基本切片之外,还可以应用以下符号:
l[start:end:step]
其中l
是一个集合,start
是一个包含索引,end
是一个排他索引,step
是一个步幅,可用于取出 中的每个第 n 个项目l
。
In [22]: l = list(range(10))
In [23]: l[::2] # Take the elements which indexes are even
Out[23]: [0, 2, 4, 6, 8]
In [24]: l[1::2] # Take the elements which indexes are odd
Out[24]: [1, 3, 5, 7, 9]
使用step
提供了一个有用的技巧来反转 Python 中的集合:
In [25]: l[::-1]
Out[25]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
也可以使用负整数,step
如下例所示:
In[28]: l[::-2]
Out[28]: [9, 7, 5, 3, 1]
但是,使用负值step
可能会变得非常混乱。此外,为了符合Python 风格,您应该避免在单个切片中使用start
、end
和step
。如果需要这样做,请考虑在两个赋值中执行此操作(一个用于切片,另一个用于跨步)。
In [29]: l = l[::2] # This step is for striding
In [30]: l
Out[30]: [0, 2, 4, 6, 8]
In [31]: l = l[1:-1] # This step is for slicing
In [32]: l
Out[32]: [2, 4, 6]
解决方案 26:
我想添加一个Hello, World!示例,为初学者解释切片的基础知识。它对我帮助很大。
让我们有一个包含六个值的列表['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']`
解决方案 27:
先前的大多数答案都解答了有关切片符号的问题。
用于切片的扩展索引语法是aList[start:stop:step]
,基本示例是:
:
更多切片示例:15 个扩展切片
解决方案 28:
以下是字符串索引的示例:
+---+---+---+---+---+
| 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
解决方案 29:
关于序列索引,需要记住的重要一点是
非负索引从序列中的第一个项目开始;
负索引从序列中的最后一项开始(因此仅适用于有限序列)。
换句话说,负索引按序列的长度向右移动:
0 1 2 3 4 5 6 7 ...
-------------------------
| a | b | c | d | e | f |
-------------------------
... -8 -7 -6 -5 -4 -3 -2 -1
考虑到这一点,订阅和切片就很简单了。
订阅
订阅使用以下语法:*
sequence[index]
sequence
订阅选择at中的单个项目index
:
>>> 'abcdef'[0]
'a'
>>> 'abcdef'[-6]
'a'
IndexError
如果index
超出范围,订阅将引发以下问题:
>>> 'abcdef'[7]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
>>> 'abcdef'[-7]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
切片
切片使用以下语法:**
sequence[start:stop:step]
切片选择 中的一系列项目sequence
,从 开始(start
包括 )到 结束stop
(不包括 ):
>>> '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'
切片默认为中最完整的项目范围,因此如果、或被省略或 ,sequence
它将使用以下默认值:*start
`stopstep
None`
step
默认为1
;如果
step
为正数start
默认为0
(第一项索引),stop
默认为start + len(sequence)
(最后一项索引加一);
if
step
为负数start
默认为-1
(最后一项索引),stop
默认为start - len(sequence)
(第一个项目索引减一)。
>>> 'abcdef'[0:6:1]
'abcdef'
>>> 'abcdef'[::]
'abcdef'
>>> 'abcdef'[-1:-7:-1]
'fedcba'
>>> 'abcdef'[::-1]
'fedcba'
ValueError
如果满足step
以下条件,切片将引发0
:
>>> 'abcdef'[::0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: slice step cannot be zero
切片不会引发IndexError
ifstart
或stop
超出范围(与订阅相反):
>>> 'abcdef'[-7:7]
'abcdef'
表达式
sequence[index]
和sequence.__getitem__(index)
是等价的。
** 表达式sequence[start:stop:step]
、sequence[slice(start, stop, step)]
和sequence.__getitem__(slice(start, stop, step))
是等价的,其中内置类slice
实例包含start
、stop
和step
。
* 表达式sequence[:]
、sequence[::]
和使用、和 的sequence[None:None:None]
默认值。start
`stop`step
解决方案 30:
我不认为Python 教程图表(在其他各种答案中引用)很好,因为这个建议适用于正步幅,但不适用于负步幅。
这是图表:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
从图表来看,我预计a[-4,-6,-1]
是的yP
,但事实是这样的ty
。
>>> a = "Python"
>>> a[2:4:1] # as expected
'th'
>>> a[-4:-6:-1] # off by 1
'ty'
始终有效的是,以字符或槽位来思考,并使用索引作为半开区间 —— 如果是正步幅,则右开;如果是负步幅,则左开。
这样,我就可以将其视为a[-4:-6:-1]
间隔a(-6,-4]
术语。
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5
-6 -5 -4 -3 -2 -1
+---+---+---+---+---+---+---+---+---+---+---+---+
| P | y | t | h | o | n | P | y | t | h | o | n |
+---+---+---+---+---+---+---+---+---+---+---+---+
-6 -5 -4 -3 -2 -1 0 1 2 3 4 5
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件