了解切片

我需要一个关于Python切片的好解释(引用是一个加分项)。

2753992 次浏览

语法是:

a[start:stop]  # items start through stop-1a[start:]      # items start through the rest of the arraya[:stop]       # items from the beginning through stop-1a[:]           # a copy of the whole array

还有step值,可以与上述任何值一起使用:

a[start:stop:step] # start through not past stop, by step

要记住的关键点是:stop值表示所选切片中的第一个值没有。因此,stopstart之间的差异是所选元素的数量(如果step为1,则默认值)。

另一个特点是startstop可能是数字,这意味着它从数组的末尾而不是开头计数。所以:

a[-1]    # last item in the arraya[-2:]   # last two items in the arraya[:-2]   # everything except the last two items

类似地,step可以是负数:

a[::-1]    # all items in the array, reverseda[1::-1]   # the first two items, reverseda[:-3:-1]  # the last two items, reverseda[-3::-1]  # everything except the last two items, reversed

如果项目比你要求的少,Python对程序员很友好。例如,如果你要求a[:-2]a只包含一个元素,你会得到一个空列表而不是错误。有时你更喜欢错误,所以你必须意识到这可能会发生。

slice对象的关系

#0对象可以表示切片操作,即:

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()对象的显式使用简化了切片的编程生成。

python教程讨论了它(向下滚动一点,直到你到达关于切片的部分)。

ASCII艺术图也有助于记住切片是如何工作的:

 +---+---+---+---+---+---+| P | y | t | h | o | n |+---+---+---+---+---+---+0   1   2   3   4   5   6-6  -5  -4  -3  -2  -1

记住切片如何工作的一种方法是将索引视为指向之间个字符,第一个字符的左边缘编号为0。然后n字符字符串的最后一个字符的右边缘具有索引n

枚举序列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)'

当我第一次看到切片语法时,有几件事对我来说并不明显:

>>> 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]

我自己使用“元素之间的索引点”方法来思考它,但有一种描述它的方式有时会帮助其他人得到它:

mylist[X:Y]

X是您想要的第一个元素的索引。
Y是不要想要的第一个元素的索引。

在使用它之后,我意识到最简单的描述是它与for循环中的参数完全相同…

(from:to:step)

其中任何一个都是可选的:

(:to:step)(from::step)(from:to)

然后负索引只需要您将字符串的长度添加到负索引即可理解它。

不管怎样,这对我来说都有效……

上面的答案没有讨论切片赋值。要理解切片赋值,向ASCII艺术添加另一个概念很有帮助:

                +---+---+---+---+---+---+| P | y | t | h | o | n |+---+---+---+---+---+---+Slice position: 0   1   2   3   4   5   6Index 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]

这也可以澄清切片和索引之间的区别。

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]==4Slice from rear:   :  -5  -4  -3  -2  -1   :b=a[:]b==[0,1,2,3,4,5] (shallow copy of a)

这只是一些额外的信息…下面的列表

>>> 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]

我发现更容易记住它是如何工作的,然后我可以找出任何特定的开始/停止/步骤组合。

首先理解range()很有启发性:

def range(start=0, stop, step=1):  # Illegal syntax, but that's the effecti = startwhile (i < stop if step > 0 else i > stop):yield ii += step

start开始,递增step,不要达到stop。非常简单。

关于负步要记住的是stop总是被排除的结束,无论是更高还是更低。如果你想以相反的顺序进行相同的切片,单独进行反转要干净得多:例如'abcde'[1:-2][::-1]从左边切掉一个字符,从右边切掉两个,然后反转。(另见#2

序列切片是相同的,除了它首先规范化负索引,并且它永远不能超出序列:

待办事项:下面的代码有一个bug,当abs(步骤)>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 boundsstart = (0 if step > 0 else len(seq)-1)if stop is None:stop = (len(seq) if step > 0 else -1)  # really -1, not last elementelif 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]只是整个字符串。

在python2.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结束(不包括bth索引处的元素)。使用上面的索引规则并记住你只会找到这个范围内的元素:

-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   11a    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]
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

您还可以使用切片赋值从列表中删除一个或多个元素:

r = [1, 'blah', 9, 8, 2, 3, 4]>>> r[1:4] = []>>> r[1, 2, 3, 4]

Python切片表示法:

a[start:end:step]
  • 对于startend,负值被解释为相对于序列的末尾。
  • end的正索引表示要包含的最后一个元素的位置之后
  • 空白值的默认值如下:[+0:-0:1]
  • 使用负步长颠倒了对startend的解释

该符号扩展到(numpy)矩阵和多维数组。例如,要对整个列进行切片,您可以使用:

m[::,0:2:] ## slice the first two columns

切片保存数组元素的引用,而不是副本。如果您想将单独的副本制作为数组,您可以使用#0

作为一般规则,使用大量硬编码索引值编写代码会导致易读性和维护混乱。例如,如果您在一年后返回代码,您将看看它,想知道当你写它时你在想什么。显示的解决方案只是一种更清楚地说明您的代码实际在做什么的方法。一般来说,内置的切片()创建一个切片对象,可以在切片的任何地方使用是允许的。例如:

>>> 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来获取有关它的更多信息分别s.start、s.stop和s.step属性。例如:

>>> a = slice(10, 50, 2)>>> a.start10>>> a.stop50>>> a.step2>>>

解释Python的切片表示法

简而言之,下标表示法(subscriptable[subscriptarg])中的冒号(:)构成切片表示法,它具有可选参数startstopstep

sliceable[start:stop:step]

Python切片是一种计算上快速的方法,可以有条不紊地访问部分数据。在我看来,即使是中级Python程序员,也必须熟悉该语言的一个方面。

重要定义

首先,让我们定义几个术语:

#0:切片的开始索引,它将包括此索引处的元素,除非它与停止相同,默认为0,即第一个索引。如果它为负数,则表示从末尾开始n项。

#0:切片的结束索引,它没有包含该索引处的元素,默认为被切片的序列的长度,即直到并包括结束。

#0:索引增加的量,默认为1。如果它为负数,则反向切片可迭代对象。

索引如何工作

您可以制作这些正数或负数中的任何一个。正数的含义很简单,但是对于负数,就像Python中的索引一样,您可以从末尾向后计数开始停止,对于步骤,您只需递减您的索引。这个例子是从留档教程,但我稍微修改了它以指示每个索引引用的序列中的哪个项目:

 +---+---+---+---+---+---+| P | y | t | h | o | n |+---+---+---+---+---+---+0   1   2   3   4   5-6  -5  -4  -3  -2  -1

切片如何工作

要将切片表示法与支持它的序列一起使用,您必须在序列后面的方括号中包含至少一个冒号(实际上是实现序列的#0方法,根据Python数据模型)。

切片符号是这样工作的:

sequence[start:stop:step]

请记住,开始停止步骤都有默认值,因此要访问默认值,只需省略参数即可。

从列表(或任何其他支持它的序列,如字符串)中获取最后九个元素的切片表示法如下所示:

my_list[-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.copylist.clear方法。)

step为负数时,startstop的默认值会改变

默认情况下,当step参数为空(或None)时,它被分配给+1

但是您可以传入一个负整数,并且列表(或大多数其他标准可切片对象)将从末尾切片到开头。

因此,负切片将更改startstop的默认值!

从源头确认这一点

我喜欢鼓励用户阅读源代码以及留档。切片对象的源代码和这个逻辑可以在这里找到。首先我们确定step是否为负:

step_is_negative = step_sign < 0;

如果是这样,下限是-1,这意味着我们一直切片并包括开头,上限是长度减1,这意味着我们从结尾开始。(请注意,这个-1的语义学是从-1开始的不同,用户可以在Python中传递索引,指示最后一项。)

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);}

然后,我们可能需要应用startstop的默认值-当step为负数时,start的默认值计算为上限:

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参数否则它将是#2参数

然后,您可以将切片对象传递给您的序列:

>>> 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非常适合此。需要注意的是,它不支持startstopstep的负参数,因此如果这是一个问题,您可能需要提前计算索引或反转可迭代对象。

length = 100last_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这样的高级对象,它可能会返回原始视图,而不是副本。

#!/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:# 000print s+'[   :   :   ]' +' = ', s[triada[0]:triada[1]:triada[2]]elif triada[0] == None and triada[1] == None and triada[2] != None:# 001print 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:# 010print 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:# 011print 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:# 100print 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:# 101print 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:# 110print 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:# 111print 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:# 00print s+'[   :   ]    ' + ' = ', s[triada[0]:triada[1]]elif triada[0] == None and triada[1] != None:# 01print s+'[   :{0:2d} ]    '.format(triada[1]) + ' = ', s[triada[0]:triada[1]]elif triada[0] != None and triada[1] == None:# 10print s+'[{0:2d} :   ]    '.format(triada[0]) + ' = ', s[triada[0]:triada[1]]elif triada[0] != None and triada[1] != None:# 11print 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 ]     =  UTECOMPUTERS[ 2 : 5 : 2 ] =  MUCOMPUTERS[-5 : 1 :-1 ] =  UPMCOMPUTERS[ 4 ]         =  UCOMPUTERS[-4 :-6 :-1 ] =  TUCOMPUTERS[ 2 :-3 : 1 ] =  MPUTCOMPUTERS[ 2 :-3 :-1 ] =COMPUTERS[   :   :-1 ] =  SRETUPMOCCOMPUTERS[-5 :   ]     =  UTERSCOMPUTERS[-5 : 0 :-1 ] =  UPMOCOMPUTERS[-5 :   :-1 ] =  UPMOCCOMPUTERS[-1 : 1 :-2 ] =  SEUM[Finished in 0.9s]

当使用负步长时,请注意答案向右移动了1。

我是这样教新手切片的:

了解索引和切片之间的区别:

Wiki Python有这个惊人的图片,它清楚地区分了索引和切片。

在此处输入图像描述

它是一个包含六个元素的列表。为了更好地理解切片,可以将该列表视为一组放置在一起的六个框。每个框中都有一个字母表。

索引就像处理盒子里的东西。你可以检查任何盒子里的东西。但是你不能一次检查多个盒子里的东西。你甚至可以替换盒子里的东西。但是你不能在一个盒子里放两个球,或者一次替换两个球。

In [122]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']
In [123]: alphaOut[123]: ['a', 'b', 'c', 'd', 'e', 'f']
In [124]: alpha[0]Out[124]: 'a'
In [127]: alpha[0] = 'A'
In [128]: alphaOut[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]: alphaOut[132]: ['a', 'b', 'c', 'd', 'e', 'f']
In [133]: alpha[0:2] = ['A', 'B']
In [134]: alphaOut[134]: ['A', 'B', 'c', 'd', 'e', 'f']
In [135]: alpha[2:2] = ['x', 'xx']
In [136]: alphaOut[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 = 1if step == 0:raise Exception("Step cannot be zero.")
if start is None:start = 0 if step > 0 else length - 1else:if start < 0:start += lengthif start < 0:start = 0 if step > 0 else -1if start >= length:start = length if step > 0 else length - 1
if stop is None:stop = length if step > 0 else -1else:if stop < 0:stop += lengthif stop < 0:stop = 0 if step > 0 else -1if stop >= length:stop = length if step > 0 else length - 1
if (step < 0 and stop >= start) or (step > 0 and start >= stop):slice_length = 0elif step < 0:slice_length = (stop - start + 1)/(step) + 1else: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]: sOut[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切片背后的智能

我的大脑似乎乐于接受lst[start:end]包含start项。我甚至可以说这是一个“自然的假设”。

但偶尔会有疑问,我的大脑要求保证它不包含第0个元素。

在这些时刻,我依赖于这个简单的定理:

for any n,    lst = lst[:n] + lst[n:]

这个漂亮的属性告诉我lst[start:end]不包含第end项,因为它在lst[end:]中。

请注意,这个定理对任何n都成立。例如,您可以检查

lst = range(10)lst[:-42] + lst[-42:] == lst

返回True

1.切片符号

为了简单起见,请记住切片只有一种形式:

s[start:end:step]

以下是它的工作原理:

  • s:一个可以被切片的对象
  • start:开始迭代的第一个索引
  • end:最后一个索引,注意#0索引不会包含在结果切片中
  • step:每个step索引选择元素

另一个导入的东西:所有#0、#1、#2都可以省略!如果它们被省略,它们的默认值将被使用:0len(s)1相应地。

所以可能的变化是:

# Mostly used variationss[start:end]s[start:]s[:end]
# Step-related variationss[:end:step]s[start::step]s[::step]
# Make a copys[:]

注意:如果start >= end(仅考虑step>0时),Python将返回一个空切片[]

2.缺陷

上面的部分解释了切片如何工作的核心特性,它将在大多数情况下工作。但是,您应该注意可能存在的陷阱,这部分解释了它们。

负指数

让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].

负阶跃

更令人困惑的是#0也可以是负数!

负步骤意味着向后迭代数组:从结束到开始,包括结束索引,并从结果中排除开始索引。

:当步骤为负时,start的默认值为len(s)(而end不等于0,因为s[::-1]包含s[0])。例如:

s[::-1]            # Reversed slices[len(s)::-1]      # The same as above, reversed slices[0:len(s):-1]     # Empty list

超出范围误差?

惊喜:当索引超出范围时,切片不会引发IndexError!

如果索引超出范围,Python会根据情况尽量将索引设置为0len(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 demonstrationIn [1]: s = [i for i in range(10)]
In [2]: sOut[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [3]: s[2:]   # From index 2 to last indexOut[3]: [2, 3, 4, 5, 6, 7, 8, 9]
In [4]: s[:8]   # From index 0 up to index 8Out[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 orderOut[9]: [9, 7, 5, 3, 1]
In [11]: s[-2::-2] # All even numbers in reversed orderOut[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 listOut[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

前面的答案没有讨论使用著名的NumPy包可以实现的多维数组切片:

切片也可以应用于多维数组。

# Here, a is a NumPy array
>>> aarray([[ 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”在第二维上操作。

下面是字符串索引的示例:

 +---+---+---+---+---+| H | e | l | p | A |+---+---+---+---+---+0   1   2   3   4   5-5  -4  -3  -2  -1
str="Name string"

切片示例:[start: end: Step]

str[start:end] # Items start through end-1str[start:]    # Items start through the rest of the arraystr[:end]      # Items from the beginning through end-1str[:]         # A copy of the whole array

下面是示例用法:

print str[0] = Nprint str[0:2] = Naprint str[0:7] = Name stprint str[0:7:2] = Nm tprint str[0:-1:2] = Nm ti

在Python中,切片的最基本形式如下:

l[start:end]

其中l是某个集合,start是包含索引,end是排他索引。

In [1]: l = list(range(10))
In [2]: l[:5] # First five elementsOut[2]: [0, 1, 2, 3, 4]
In [3]: l[-5:] # Last five elementsOut[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 oneOut[7]: [0, 1, 2, 3, 4, 5, 6, 7, 8]
In [8]: l[-3:] # Take the last three elementsOut[8]: [7, 8, 9]

可以提供切片时超出边界的索引,例如:

In [9]: l[:20] # 20 is out of index bounds, and l[20] will raise an IndexError exceptionOut[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 exceptionOut[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]: lOut[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]: lOut[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_copyOut[15]: True

如果在执行赋值操作时省略开始索引和结束索引,则集合的整个内容将被引用内容的副本替换:

In [20]: l[:] = list('hello...')
In [21]: lOut[21]: ['h', 'e', 'l', 'l', 'o', '.', '.', '.']

除了基本的切片,还可以应用以下符号:

l[start:end:step]

其中l是一个集合,start是一个包含索引,end是一个独占索引,step是一个步幅,可用于获取l中的每个第n项。

In [22]: l = list(range(10))
In [23]: l[::2] # Take the elements which indexes are evenOut[23]: [0, 2, 4, 6, 8]
In [24]: l[1::2] # Take the elements which indexes are oddOut[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使用负值可能会变得非常混乱。此外,为了成为Pythonic,您应该避免在单个切片中使用startendstep。如果需要,请考虑在两个作业中执行此操作(一个用于切片,另一个用于跨步)。

In [29]: l = l[::2] # This step is for striding
In [30]: lOut[30]: [0, 2, 4, 6, 8]
In [31]: l = l[1:-1] # This step is for slicing
In [32]: lOut[32]: [2, 4, 6]

前面的大多数答案都澄清了关于切片表示法的问题。

用于切片的扩展索引语法是aList[start:stop:step],基本示例如下:

在此处输入图像描述

更多切片示例:15加长切片

在我看来,如果你按照以下方式看,你会更好地理解和记忆Python字符串切片符号(继续阅读)。

让我们使用以下字符串…

azString = "abcdefghijklmnopqrstuvwxyz"

对于那些不知道的人,您可以使用符号azString[x:y]azString创建任何子字符串

来自其他编程语言,这就是常识受到损害的时候。什么是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设置为将围绕所需子字符串的值。例如,要获取子字符串“cdesgh”,您可以使用azString[2:8],因为“c”左侧的索引为2,“h”右侧的索引为8。

请记住,我们正在设置边界。这些边界是您可以放置一些括号的位置,这些括号将缠绕在子字符串上,就像这样…

a b[ c d e f g h] i j

这个把戏一直有效,很容易记住。

如果你觉得切片中的负索引令人困惑,这里有一个非常简单的方法来考虑它:只需将负索引替换为len - index。例如,将-3替换为len(list) - 3

说明切片在内部做什么的最好方法就是在实现此操作的代码中显示它:

def slice(list, start = None, end = None, step = 1):# Take care of missing start/end parametersstart = 0 if start is None else startend = len(list) if end is None else end
# Take care of negative start/end parametersstart = len(list) + start if start < 0 else startend = len(list) + end if end < 0 else end
# Now just execute a for-loop with start, end and stepreturn [list[i] for i in range(start, end, 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']

基本的切片技术是定义起点,停止点和步长-也称为步幅。

首先,我们将创建一个在切片中使用的值列表。

创建两个列表进行切片。第一个是从1到9的数字列表(列表A)。第二个也是从0到9的数字列表(列表B):

A = list(range(1, 10, 1)) # Start, stop, and stepB = list(range(9))
print("This is List A:", A)print("This is List B:", B)

从A中索引数字3,从B中索引数字6。

print(A[2])print(B[6])

基本切片

用于切片的扩展索引语法是aList[start:stop:step]。开始参数和步骤参数都默认为None-唯一需要的参数是停止。您是否注意到这与使用范围定义列表A和B的方式相似?这是因为切片对象表示range(start, stop, step)指定的索引集。

如您所见,仅定义停止返回一个元素。由于start默认为无,这意味着只检索一个元素。

需要注意的是,第一个元素是索引0,没有索引1。这就是为什么我们在这个练习中使用2个列表。列表A的元素根据顺序位置编号(第一个元素是1,第二个元素是2,等等)而列表B的元素是用于索引它们的数字(第一个元素为0,0,等等)。

使用扩展索引语法,我们检索一系列值。例如,所有值都使用冒号检索。

A[:]

要检索元素的子集,需要定义开始和停止位置。

给定模式aList[start:stop],从List A中检索前两个元素。

如果我们可以将切片与range联系起来,这很容易理解,range给出了索引。我们可以将切片分为以下两类:


1.没有步骤或步骤>0。例如,[i:j][i:j:k](k>0)

假设序列是s=[1,2,3,4,5]

  • 如果0<i<len(s)0<j<len(s),那么[i:j:k] -> range(i,j,k)

例如,[0:3:2] -> range(0,3,2) -> 0, 2

  • 如果i>len(s)j>len(s),那么i=len(s)j=len(s)

例如,[0:100:2] -> range(0,len(s),2) -> range(0,5,2) -> 0, 2, 4

  • 如果i<0j<0,那么i=max(0,len(s)+i)j=max(0,len(s)+j)

例如,[0:-3:2] -> range(0,len(s)-3,2) -> range(0,2,2) -> 0

另一个例子,[0:-1:2] -> range(0,len(s)-1,2) -> range(0,4,2) -> 0, 2

  • 如果未指定i,则i=0

例如,[:4:2] -> range(0,4,2) -> range(0,4,2) -> 0, 2

  • 如果未指定j,则j=len(s)

例如,[0::2] -> range(0,len(s),2) -> range(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(s),那么[i:j:k] -> range(i,j,k)

例如,[5:0:-2] -> range(5,0,-2) -> 5, 3, 1

  • 如果i>len(s)j>len(s),那么i=len(s)-1j=len(s)-1

例如,[100:0:-2] -> range(len(s)-1,0,-2) -> range(4,0,-2) -> 4, 2

  • 如果i<0j<0,那么i=max(-1,len(s)+i)j=max(-1,len(s)+j)

例如,[-2:-10:-2] -> range(len(s)-2,-1,-2) -> range(3,-1,-2) -> 3, 1

  • 如果未指定i,则i=len(s)-1

例如,[:0:-2] -> range(len(s)-1,0,-2) -> range(4,0,-2) -> 4, 2

  • 如果未指定j,则j=-1

例如,[2::-2] -> range(2,-1,-2) -> 2, 0

另一个例子,[::-1] -> range(len(s)-1,-1,-1) -> range(4,-1,-1) -> 4, 3, 2, 1, 0


总结

在此处输入图片描述

我不认为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

我有点沮丧,因为没有找到一个在线资源,或者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 pertainsto 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_MAXif step is None:step = 1elif step == 0:raise ValueError('slice step cannot be zero')
if start is None:start = maxint if step < 0 else 0if 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.clength = len(x)slice_length = 0
if start < 0:start += lengthif start < 0:start = -1 if step < 0 else 0elif start >= length:start = length - 1 if step < 0 else length
if stop < 0:stop += lengthif stop < 0:stop = -1 if step < 0 else 0elif stop > length:stop = length - 1 if step < 0 else length
if step < 0:if stop < start:slice_length = (start - stop - 1) // (-step) + 1else:if start < stop:slice_length = (stop - start - 1) // step + 1
# Cases of step = 1 and step != 1 are treated separatelyif slice_length <= 0:return []elif step == 1:# See list_slice() in listobject.cresult = []for i in range(stop - start):result.append(x[i+start])return resultelse:result = []cur = startfor i in range(slice_length):result.append(x[cur])cur += stepreturn result

我个人认为这是一个for循环:

a[start:end:step]# for(i = start; i < end; i += step)

另外,请注意,startend的负值是相对于列表末尾的,并且在上面的示例中由given_index + a.shape[0]计算。

切片的规则如下:

[lower bound : upper bound : step size]

I-upper boundlower 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)

它将返回一个空字符串

(二)如果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)。

关于序列的索引要记住的重要思想是

  • 非负索引从序列中的第一项开始;
  • 索引从序列中的最后项开始(因此仅适用于有限序列)。

换句话说,负索引右移序列的长度:

              0   1   2   3   4   5   6   7   ...-------------------------| a | b | c | d | e | f |-------------------------...  -8  -7  -6  -5  -4  -3  -2  -1

考虑到这一点,订阅切片很简单。

订阅

订阅使用以下语法:*

sequence[index]

订阅选择sequenceindex处的单个项目:

>>> 'abcdef'[0]'a'>>> 'abcdef'[-6]'a'

订阅会为超出范围的index引发IndexError

>>> 'abcdef'[100]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中的最充分范围,因此它对省略或等于None的任何startstopstep使用以下默认值:***

  • step默认为1
  • 如果step为正
    • start默认为0(第一项索引),
    • stop默认为start + len(sequence)(最后一项索引加1);
  • 如果step为负
    • start默认为-1(最后一项索引),
    • stop默认为start - len(sequence)(第一项索引减一)。
>>> 'abcdef'[0:6:1]'abcdef'>>> 'abcdef'[::]'abcdef'>>> 'abcdef'[-1:-7:-1]'fedcba'>>> 'abcdef'[::-1]'fedcba'

切片会为等于零的step引发ValueError

>>> 'abcdef'[::0]Traceback (most recent call last):File "<stdin>", line 1, in <module>ValueError: slice step cannot be zero

切片不会为超出范围的startstop引发IndexError(与订阅相反):

>>> 'abcdef'[-100:100]'abcdef'

*表达式sequence[index]sequence.__getitem__(index)是等价的。

**表达式sequence[start:stop:step]sequence[slice(start, stop, step)]sequence.__getitem__(slice(start, stop, step))是等效的,其中内置类#3实例打包startstopstep

***表达式sequence[:]sequence[::]sequence[None:None:None]startstopstep使用默认值。

已经有很多答案了,但我想添加一个性能比较

~$ python3.8 -m timeit -s 'fun = "this is fun;slicer = slice(0, 3)"' "fun_slice = fun[slicer]"10000000 loops, best of 5: 29.8 nsec per loop~$ python3.8 -m timeit -s 'fun = "this is fun"' "fun_slice = fun[0:3]"10000000 loops, best of 5: 37.9 nsec per loop~$ python3.8 -m timeit -s 'fun = "this is fun"' "fun_slice = fun[slice(0, 3)]"5000000 loops, best of 5: 68.7 nsec per loop~$ python3.8 -m timeit -s 'fun = "this is fun"' "slicer = slice(0, 3)"5000000 loops, best of 5: 42.8 nsec per loop

因此,如果您重复使用同一个切片,使用切片对象将是有益的并提高易读性。然而,如果您只切片几次,则应首选[:]符号。

这里有一个简单的记忆它是如何工作的:

  • S L *I* C *E*
  • 切片的'i'排在第一位,代表包容
  • “e”排在最后,代表独家

所以array[j:k]包括作为第1个元素,排除作为第2个元素。