我需要一个关于Python切片表示法的好解释(引用是一个加分项)。
对我来说,这个符号需要理解一下。
它看起来非常强大,但我还没有完全理解它。
其实很简单:
1 2 3 4 | 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 |
还有
1 | a[start:stop:step] # start through not past stop, by step |
要记住的关键点是
另一个特性是
1 2 3 | a[-1] # last item in the array a[-2:] # last two items in the array a[:-2] # everything except the last two items |
同样,
1 2 3 4 | 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对程序员很友好。例如,如果您要求
切片操作符
1 | a[start:stop:step] |
等价于:
1 | a[slice(start, stop, step)] |
根据参数的数量,Slice对象的行为也略有不同,类似于
虽然基于
Python教程对此进行了讨论(向下滚动一点,直到看到关于切片的部分)。
ASCII艺术图表也有助于记住切片是如何工作的:
1 2 3 4 5 | +---+---+---+---+---+---+ | P | y | t | h | o | n | +---+---+---+---+---+---+ 0 1 2 3 4 5 6 -6 -5 -4 -3 -2 -1 |
One way to remember how slices work is to think of the indices as pointing between characters, with the left edge of the first character numbered 0. Then the right edge of the last character of a string of n characters has index n.
列举文法容许的可能性:
1 2 3 4 5 6 7 8 | >>> seq[:] # [seq[0], seq[1], ..., seq[-1] ] >>> seq[low:] # [seq[low], seq[low+1], ..., seq[-1] ] >>> seq[:high] # [seq[0], seq[1], ..., seq[high-1]] >>> seq[low:high] # [seq[low], seq[low+1], ..., seq[high-1]] >>> seq[::stride] # [seq[0], seq[stride], ..., seq[-1] ] >>> seq[low::stride] # [seq[low], seq[low+stride], ..., seq[-1] ] >>> seq[:high:stride] # [seq[0], seq[stride], ..., seq[high-1]] >>> seq[low:high:stride] # [seq[low], seq[low+stride], ..., seq[high-1]] |
当然,如果
如果
1 2 3 4 | >>> seq[::-stride] # [seq[-1], seq[-1-stride], ..., seq[0] ] >>> seq[high::-stride] # [seq[high], seq[high-stride], ..., seq[0] ] >>> seq[:low:-stride] # [seq[-1], seq[-1-stride], ..., seq[low+1]] >>> seq[high:low:-stride] # [seq[high], seq[high-stride], ..., seq[low+1]] |
扩展切片(使用逗号和省略号)主要只用于特殊的数据结构(如NumPy);基本序列不支持它们。
1 2 3 4 5 6 | >>> class slicee: ... def __getitem__(self, item): ... return `item` ... >>> slicee()[0, 1:2, ::5, ...] '(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)' |
上面的答案没有讨论切片分配。为了理解片分配,在ASCII艺术中添加另一个概念是有帮助的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | +---+---+---+---+---+---+ | 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'] |
一个启发式是,对于从0到n的切片,可以这样想:"0是开始,从开始处开始,取列表中的n个项"。
1 2 3 4 5 6 | >>> 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'] |
另一种启发式是,"对于任何切片,将开始部分替换为0,应用前面的启发式得到列表的末尾,然后重新计算第一个数字,将开始部分删除。"
1 2 3 4 5 6 7 | >>> 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. |
切片分配的第一条规则是,由于切片返回一个列表,切片分配需要一个列表(或其他可迭代的):
1 2 3 4 5 6 7 8 9 | >>> 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 |
切片赋值的第二条规则,你也可以在上面看到,就是无论切片索引返回列表的哪一部分,切片赋值所改变的部分都是相同的:
1 2 3 4 5 | >>> p[2:4] ['T','h'] >>> p[2:4] = ['t','r'] >>> p ['P','y','t','r','o','n'] |
切片赋值的第三条规则是,赋值列表(iterable)不必具有相同的长度;索引切片被简单地切掉,然后被分配给它的东西全部替换掉:
1 2 3 4 | >>> 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很容易让你的脑袋转到索引一个空切片:
1 2 3 4 5 6 7 8 9 10 11 | >>> 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] [] |
一旦你看到了,切片分配给空切片也是有意义的:
1 2 3 4 5 6 7 8 9 10 11 12 | >>> 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"相对,即使是在分配空片时也是如此。因此,空片赋值的位置是非空片赋值位置的逻辑扩展。
倒回去一点,当你继续我们开始计算切片的时候会发生什么?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | >>> 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中,除非使用负数显式地请求它们,否则不会得到负的步长。
1 2 | >>> p[5:3:-1] ['n','o'] |
有一些奇怪的后果"一旦你做了,你做的"规则:
1 2 3 4 5 6 7 8 9 10 | >>> 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切片具有奇怪的防错性:
1 2 3 4 | >>> p[100:200] [] >>> p[int(2e99):int(1e99)] [] |
这有时很有用,但也会导致一些奇怪的行为:
1 2 3 4 5 | >>> 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'] |
根据你的申请,这可能……也可能不会…正如你所希望的那样!
<人力资源/ >下面是我最初的答案。它对很多人都很有用,所以我不想删除它。
1 2 3 4 5 6 7 8 9 | >>> 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] |
这也可能阐明切片和索引之间的区别。
Explain Python's slice notation
简而言之,下标表示法(
1 | sliceable[start:stop:step] |
Python切片是一种计算速度快的方法,可以有条不紊地访问数据的一部分。在我看来,即使是一个中级Python程序员,也需要熟悉Python语言的一个方面。
重要定义
首先,让我们定义几个术语:
start: the beginning index of the slice, it will include the element at this index unless it is the same as stop, defaults to 0, i.e. the first index. If it's negative, it means to start
n items from the end.stop: the ending index of the slice, it does not include the element at this index, defaults to length of the sequence being sliced, that is, up to and including the end.
step: the amount by which the index increases, defaults to 1. If it's negative, you're slicing over the iterable in reverse.
索引是如何工作的
你可以取这些正数或负数中的任何一个。正数的含义很简单,但是对于负数,就像Python中的索引一样,从末尾开始和结束向后计数,对于步骤,只需减少索引。这个例子来自于文档的教程,但是我稍微修改了一下,以指示每个索引引用序列中的哪个项:
1 2 3 4 5 | +---+---+---+---+---+---+ | P | y | t | h | o | n | +---+---+---+---+---+---+ 0 1 2 3 4 5 -6 -5 -4 -3 -2 -1 |
切片是如何工作的
要对支持它的序列使用切片表示法,必须在序列后面的方括号中包含至少一个冒号(根据Python数据模型,它实际上实现了序列的
切片表示法是这样工作的:
1 | sequence[start:stop:step] |
记住,start、stop和step都有默认值,因此要访问默认值,只需忽略参数。
切片表示法从列表(或任何其他支持它的序列,如字符串)中获取最后九个元素,如下所示:
1 | my_list[-9:] |
当我看到这个的时候,我把括号里的部分读成"9从末尾到末尾"。(实际上,我在心里把它缩写为"-9,on")
解释:
完整的符号是
1 | my_list[-9:None:None] |
替换默认值(实际上,当
1 | my_list[-9:len(my_list):1] |
冒号
1 | list_copy = sequence[:] |
清除它们的方法是:
1 | del my_list[:] |
(Python 3获得一个
默认情况下,当
但是您可以传入一个负整数,列表(或大多数其他标准切片)将从末尾被切片到开头。
因此,一个负片将更改
我希望鼓励用户阅读源代码和文档。切片对象的源代码和这个逻辑可以在这里找到。首先我们确定
1 step_is_negative = step_sign < 0;
如果是这样,下界是
1
2
3
4
5
6
7
8
9 if (step_is_negative) {
lower = PyLong_FromLong(-1L);
if (lower == NULL)
goto error;
upper = PyNumber_Add(length, lower);
if (upper == NULL)
goto error;
}
否则
1
2
3
4
5
6 else {
lower = _PyLong_Zero;
Py_INCREF(lower);
upper = length;
Py_INCREF(upper);
}
然后,我们可能需要为
1
2
3
4 if (self->start == Py_None) {
start = step_is_negative ? upper : lower;
Py_INCREF(start);
}
和
1
2
3
4 if (self->stop == Py_None) {
stop = step_is_negative ? lower : upper;
Py_INCREF(stop);
}
给你的切片一个描述性的名字
您可能会发现将形成切片与将其传递给
然而,您不能仅仅将一些用冒号分隔的整数分配给变量。你需要使用切片对象:
1 | last_nine_slice = slice(-9, None) |
第二个参数
然后你可以将切片对象传递给你的序列:
1 2 | >>> list(range(100))[last_nine_slice] [91, 92, 93, 94, 95, 96, 97, 98, 99] |
有趣的是,范围也可以切片:
1 2 | >>> range(100)[last_nine_slice] range(91, 100) |
内存注意事项:
由于Python列表的切片在内存中创建新对象,另一个需要注意的重要函数是
1 2 3 | length = 100 last_nine_iter = itertools.islice(list(range(length)), length-9, None, 1) list_last_nine = list(last_nine_iter) |
现在:
1 2 | >>> list_last_nine [91, 92, 93, 94, 95, 96, 97, 98, 99] |
列表切片复制的事实是列表本身的一个特性。如果要分割像panda DataFrame这样的高级对象,它可能会返回原始视图,而不是副本。
当我第一次看到切分语法时,有几件事我并没有马上意识到:
1 2 3 | >>> x = [1,2,3,4,5,6] >>> x[::-1] [6,5,4,3,2,1] |
反转序列的简单方法!
如果你想,出于某种原因,每第二项的顺序颠倒一下:
1 2 3 | >>> x = [1,2,3,4,5,6] >>> x[::-2] [6,4,2] |
在Python 2.7
切片在Python中
1 2 3 4 5 6 7 8 9 | [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). |
理解索引分配是非常重要的。
1 2 3 | 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索引处的元素)。使用上面的索引规则,记住你只能找到这个范围内的元素:
1 | -len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1 |
但这个范围在两个方向上无限延伸:
1 | ...,-len -2 ,-len-1,-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1, len, len +1, len+2 , .... |
例如:
1 2 3 | 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相等,那么你也会得到一个空列表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | >>> 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] |
在http://wiki.python.org/moin/movingtopythonfrommotherlanguages上找到了这个很棒的表
1 2 3 4 5 6 7 8 9 10 11 12 | 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) |
在使用它之后,我意识到最简单的描述是它与
1 | (from:to:step) |
其中任何一个都是可选的:
1 2 3 | (:to:step) (from::step) (from:to) |
然后负索引只需要把字符串的长度加到负索引上就可以理解了。
不管怎样,这对我很有用……
我发现更容易记住它是如何工作的,然后我就可以计算出任何特定的开始/停止/步骤组合。
首先理解
1 2 3 4 5 | 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 |
从
关于负步骤要记住的是,
序列切片是一样的,只是它首先对负索引进行归一化,并且永远不能超出序列:
TODO:当abs(step)>1时,下面的代码有一个bug,"永远不要超出序列";我想我把它打对了,但是很难理解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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] |
不要担心
正态化负索引首先允许从末尾独立地计算start和/或stop:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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
我使用"元素间的索引点"方法来思考它,但是描述它的一种方法是这样的:
1 | mylist[X:Y] |
X是你想要的第一个元素的下标。Y是你不想要的第一个元素的下标。
Python切片符号:
1 | a[start:end:step] |
对于
符号扩展到(numpy)矩阵和多维数组。例如,要分割整个列,可以使用:
1 | m[::,0:2:] ## slice the first two columns |
片包含数组元素的引用,而不是副本。如果想单独复制一个数组,可以使用
我是这样教新手切片的:
理解索引和切片之间的区别:
Wiki Python有这张令人惊奇的图片,它清楚地区分了索引和切片。
它是一个包含6个元素的列表。为了更好地理解切片,可以将该列表视为一组六个框放在一起的列表。每个盒子里都有一个字母表。
索引就像处理方框的内容。您可以检查任何框的内容。但你不能同时检查多个框的内容。您甚至可以替换框中的内容。但是你不能把两个球放在一个盒子里或者一次换两个球。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 |
切片就像处理盒子本身。你可以拿起第一个盒子放在另一张桌子上。要拿起箱子,你所需要知道的只是开始和开始的位置。盒子的末端。
您甚至可以取前3箱或后2箱,或1箱与1箱之间的所有箱。4. 所以,你可以选择任何一组盒子,如果你知道开始和结束;的结局。这个职位叫做start &停止的位置。
有趣的是,您可以同时替换多个框。你也可以把多个盒子放在任何你喜欢的地方。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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'] |
切片与步骤:
直到现在你还在不停地捡箱子。但有些时候你需要谨慎地挑选。例如,你可以每隔一秒拿一个盒子。你甚至可以每隔三分之一的盒子从最后拿起。这个值称为步长。这表示连续拾取的间隔。如果你从头到尾挑选盒子,那么步长应该是正的,反之亦然。
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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对象&可选参数切片和返回开始,停止,步骤和放大器;请求切片的切片长度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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的函数,所以可以传递一些参数。检查它计算缺失参数的能力。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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] |
注:这篇文章最初写在我的博客http://www.avilpage.com/2015/03/a- piece of pythonintelligens-behind.html
这只是一些额外的信息…考虑下面的列表
1 | >>> l=[12,23,345,456,67,7,945,467] |
扭转这一趋势的其他技巧很少:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> 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] |
参见上面abc的回答
您还可以使用切片分配来删除列表中的一个或多个元素:
1 2 3 4 | r = [1, 'blah', 9, 8, 2, 3, 4] >>> r[1:4] = [] >>> r [1, 2, 3, 4] |
一般来说,编写带有大量硬编码索引值的代码会提高可读性和维护混乱。例如,如果您在一年后再回到代码,您将会看着它,想想你写它的时候在想什么。所示的解决方案只是一种更清楚地说明代码实际在做什么的方法。通常,内置的slice()创建一个slice对象,该对象可以在片的任何地方使用是被允许的。例如:
1 2 3 4 5 6 7 8 9 10 11 12 | >>> 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] |
如果您有一个slice实例s,您可以通过查看它来获得关于它的更多信息年代。首先,s。停止和年代。一步属性,分别。例如:
1
2
3
4
5
6
7
8 >>> a = slice(10, 50, 2)
>>> a.start
10
>>> a.stop
50
>>> a.step
2
>>>
1。片符号
使它简单,记得片只有一种形式:
1 | s[start:end:step] |
它是这样工作的:
另一个重要的东西:所有
所以可能的变化是:
1 2 3 4 5 6 7 8 9 10 11 12 | # 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[:] |
注意:如果
2。陷阱
上面的部分解释了slice工作原理的核心特性,它在大多数情况下都会工作。然而,也可能会有一些陷阱,您应该小心,本部分将对此进行解释。
负索引
首先让python学习者感到困惑的是索引可以是负数!不要惊慌:负指数的意思是向后计数。
例如:
1 2 3 4 | s[-5:] # start at the 5th index from the end of array, # thus returns the last 5 elements s[:-5] # start at index 0, end until the 5th index from end of array, # thus returns s[0:len(s)-5] |
-
步
更令人困惑的是
负步骤意味着向后迭代数组:从结束到开始,包含结束索引,并从结果中排除开始索引。
注意:当step为负数时,
1 2 3 | s[::-1] # reversed slice s[len(s)::-1] # same as above, reversed slice s[0:len(s):-1] # empty list |
超出范围错误?
吃惊:当指数超出范围时切片不提高硬度!
如果索引超出范围,python会根据情况将索引设置为
1 2 3 | s[:len(s)+5] # same as s[:len(s)] s[-len(s)-5::] # same as s[0:] s[len(s)+5::-1] # same as s[len(s)::-1], same as s[::-1] |
3。示例
让我们用例子来结束这个答案,解释我们讨论过的所有问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | # 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, 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 IndexError --------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-15-79ffc22473a3> in <module>() ----> 1 s[11] IndexError: list index out of range |
以上答案不讨论多维数组切片,这是可能使用著名的numpy包:
切片也适用于多维数组。
1 2 3 4 5 6 7 8 9 | # 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"作用于第二个维度。
我的大脑似乎乐于接受
但偶尔也会有疑问,我的大脑会要求我保证它不包含
在这些时刻,我依靠这个简单的定理:
1 | for any n, lst = lst[:n] + lst[n:] |
这个漂亮的属性告诉我
注意,这个定理对任何
1 2 | lst = range(10) lst[:-42] + lst[-42:] == lst |
返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | #!/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) |
您可以运行这个脚本并使用它进行实验,下面是我从脚本中获得的一些示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | +---+---+---+---+---+---+---+---+---+ | 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。
在Python中,最基本的切片形式如下:
其中
1 2 3 4 5 6 7 | 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] |
从开始切片时,可以省略zero索引;从切片到结束时,可以省略final索引,因为它是冗余的,所以不要太冗长:
1 2 3 4 5 | In [5]: l[:3] == l[0:3] Out[5]: True In [6]: l[7:] == l[7:len(l)] Out[6]: True |
当执行相对于集合末尾的偏移时,负整数很有用:
1 2 3 4 5 | 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 3 elements Out[8]: [7, 8, 9] |
可以在切片时提供超出边界的索引,例如:
1 2 3 4 5 | In [9]: l[:20] # 20 is out of index bounds, 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, l[-20] will raise an IndexError exception Out[11]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
请记住,分割一个集合的结果是一个全新的集合。此外,当在赋值中使用片符号时,片赋值的长度不需要相同。将保留分配切片前后的值,集合将收缩或增长以包含新值:
1 2 3 4 5 6 7 8 9 | In [16]: l[2:6] = list('abc') # assigning less 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] |
如果你省略了开始和结束索引,你会复制集合:
1 2 3 4 | In [14]: l_copy = l[:] In [15]: l == l_copy and l is not l_copy Out[15]: True |
如果在执行赋值操作时省略开始和结束索引,则集合的全部内容将替换为引用内容的副本:
1 2 3 4 | In [20]: l[:] = list('hello...') In [21]: l Out[21]: ['h', 'e', 'l', 'l', 'o', '.', '.', '.'] |
除了基本的切片,还可以应用以下符号:
1 | l[start:end:step] |
其中
1 2 3 4 5 6 7 | 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] |
使用
1 2 | In [25]: l[::-1] Out[25]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] |
也可以对
1 2 | In[28]: l[::-2] Out[28]: [9, 7, 5, 3, 1] |
然而,为
1 2 3 4 5 6 7 8 9 | 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] |
上面的大部分答案都澄清了切片表示法。用于切片的扩展索引语法是
:
更多的切片示例:15个扩展切片
下面是字符串索引的例子
1 2 3 4 5 6 7 | +---+---+---+---+---+ | H | e | l | p | A | +---+---+---+---+---+ 0 1 2 3 4 5 -5 -4 -3 -2 -1 str="Name string" |
切片的例子:[开始:结束步骤):
1 2 3 4 | 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 |
下面是示例用法
1 2 3 4 5 | 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 |
我想添加一个Hello world示例,为非常初学者解释切片的基础知识。它帮了我很多。
让我们有一个包含6个值的列表
1 2 3 4 | +---+---+---+---+---+---+ | P | Y | T | H | O | N | +---+---+---+---+---+---+ 0 1 2 3 4 5 |
这个列表中最简单的部分是它的子列表。符号是
1 | [ start cutting before this index : end cutting before this index ] |
现在如果你对上面的列表进行切片
1 2 3 4 5 | | | +---+---|---+---+---|---+ | P | Y | T | H | O | N | +---+---|---+---+---|---+ 0 1 | 2 3 4 | 5 |
您在索引为
呵呵呵,看到自己在2600多人投票后试图给出一个更好更简单的解释,这有点奇怪。
我们开始…
在我看来,如果您按照以下方式查看Python字符串切片表示法,您将更好地理解和记忆它。
让我们用下面的字符串…
1 | azString ="abcdefghijklmnopqrstuvwxyz" |
对于不知道的人,可以使用
来自其他编程语言,这是常识受到损害的时候。x和y是什么?
我不得不坐下来,运行几个场景来寻求一种记忆技巧,它将帮助我记住x和y是什么,并在第一次尝试时帮助我正确地分割字符串。
我的结论是,x和y应该被看作是围绕我们想要添加的字符串的边界索引。因此,我们应该看到表达式为
这里有一个可视化的例子。
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",可以使用
记住,我们是在设定界限。
这个技巧一直都很有效,而且很容易记住。
希望这能有所帮助。
如果您觉得切片中的负索引令人困惑,这里有一个非常简单的方法来考虑:用
最好的方法来说明切片在内部做什么,只是显示它在代码中实现这个操作:
1 2 3 4 5 6 7 8 9 10 11 | def slice(list, start = None, end = None, step = 1): # take care of missing start/end parameters start = 0 if start is None else start end = len(list) if end is None else end # take care of negative start/end parameters start = len(list) + start if start < 0 else start end = len(list) + end if end < 0 else end # now just execute for-loop with start, end and step return [list[i] for i in range(start, end, step)] |
切片:-蛇出现在你的脚附近。它从无形变为有形。我们的视野只显示了世界的一部分。类似地,Python切片根据开始和停止提取元素。我们在Python中对许多类型进行切片。我们指定一个可选的第一个索引、一个可选的最后一个索引和一个可选步骤。
1 2 3 4 5 | values[1:3] Index 1 through index 3. values[2:-1] Index 2 through index one from last. values[:2] Start through index 2. values[2:] Index 2 through end. values[::2] Start through end, skipping ahead 2 places each time. |
你可以得到很好的例子在下面的链接:-python切片表示法示例
基本的切片技术是定义起始点、停止点和步长(也称为步长)。
首先,我们将创建一个值列表,用于切片。
创建两个要切片的列表,第一个是从1到9的数字列表(列表a)。第二个也是一个数字列表,从0到9(列表B)
1 2 3 4 5 | A = list(range(1,10,1)) # start,stop,step B = list(range(9)) print("This is List A:",A) print("This is List B:",B) |
索引A中的3和B中的6。
1 2 | print(A[2]) print(B[6]) |
基本的切片
用于切片的扩展索引语法是aList[start:stop:step]。start参数和step参数都默认为none—惟一需要的参数是stop。您是否注意到这类似于使用range来定义列表A和B?这是因为slice对象表示range(start、stop、step)指定的一组索引。Python 3.4的文档
可以看到,只定义stop返回一个元素。由于start默认为none,这意味着只检索一个元素。
需要注意的是,第一个元素是索引0,而不是索引1。这就是为什么我们在这个练习中使用两个列表。列表A的元素根据序号位置进行编号(第一个元素是1,第二个元素是2,等等),而列表B的元素是用来索引它们的数字(第一个元素0的[0],等等)。
使用扩展索引语法,我们检索一系列值。例如,所有值都用冒号检索。
1 | A[:] |
要检索元素的子集,需要定义开始和停止位置。
给定pattern aList[start:stop],从列表A检索前两个元素
如果我们能将切片与
1。没有步骤或步骤> 0。例如,[i:j] 或[i:j:k] (k>0)
假设序列是
例如,
例如,
例如,
另一个例子是
例如,
例如,
2。< 0。例如,[i:j:k] (k<0)
假设序列是
例如,
例如,
例如,
例如,
例如,
另一个例子是
总之
上面的每个人都解释得很好。我想给它加上一个简单的解释。As:是一个切片操作符,它排除后面提到的数组索引(:),包括前面提到的数组索引(:)。例如
[included array indices starting index:excluded array starting index]
a[-1] # last item in the array (included)
a[-2:] # only last two items in the array (included)
a[:-2] # everything except the last two items(excluded)
a[:] # all the items in the array are included