我需要在Python的切片表示法上有一个很好的解释(引用是一个加号).
对我来说,这种符号需要一点点提升.
它看起来非常强大,但我还没有完全了解它.
它非常简单:
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
值表示不在所选切片中的第一个值.所以,之间的差stop
和start
是选择的元素的数量(如果step
是1,默认值).
另一个特征是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)]
切片对象也表现略有不同,这取决于参数的个数,同样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.
列举语法允许的可能性:
>>> 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]]
当然,如果(high-low)%stride != 0
,那么终点将会略低于high-1
.
如果stride
是负数,则排序会因为我们倒计时而改变一点:
>>> 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)使用; 基本序列不支持它们.
>>> class slicee: ... def __getitem__(self, item): ... return repr(item) ... >>> slicee()[0, 1:2, ::5, ...] '(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
上面的答案不讨论切片分配.要理解切片分配,为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 "", line 1, in 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 "", line 1, in 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]
这也可以澄清切片和索引之间的区别.
解释Python的切片表示法
总之,冒号(:
)在标符号(subscriptable[subscriptarg]
)使切片符号-它具有可选参数,start
,stop
,step
:
sliceable[start:stop:step]
Python切片是一种有条不紊地访问部分数据的计算速度快的方法.在我看来,要成为一名中级Python程序员,这是必须熟悉的语言的一个方面.
首先,让我们定义一些术语:
start:切片的开始索引,它将包含此索引处的元素,除非它与stop相同,默认为0,即第一个索引.如果它是否定的,则意味着
n
从最后开始项目.停止:切片的结束索引,但它不包括这个索引处的元素,默认为序列的长度被切片,也就是,直到并包括端部.
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]
并且回想一下,启动,停止和步骤都有默认值,因此要访问默认值,只需省略参数即可.
从列表中获取最后九个元素的切片表示法(或任何其他支持它的序列,如字符串)将如下所示:
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
和list.clear
方法.)
step
为负时,默认为start
和stop
更改默认情况下,当step
参数为空(或None
)时,将其分配给+1
.
但是你可以传入一个负整数,列表(或大多数其他标准的可切片)将从最后到开头进行切片.
因此负片将改变默认值start
和stop
!
我想鼓励用户阅读源代码和文档.切片对象的源代码和此逻辑可在此处找到.首先我们确定是否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); }
然后,我们可能需要应用默认值start
和stop
- 默认然后for 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这样的高级对象,它可能会返回原始视图,而不是副本.
当我第一次看到切片语法时,有些事情对我来说并不是很明显:
>>> 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]
在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结束(不包括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 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]
在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)
稍微使用它之后,我意识到最简单的描述是它与for
循环中的参数完全相同...
(from:to:step)
其中任何一个都是可选的:
(:to:step) (from::step) (from:to)
然后负索引只需要你将字符串的长度添加到负索引以理解它.
无论如何这对我有用......
我发现它更容易记住它是如何工作的,然后我可以找出任何特定的开始/停止/步骤组合.
首先要了解它是有益的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]
,只是整个字符串.
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
我自己使用"元素之间的索引点"方法来思考它,但是一种描述它的方法有时会帮助其他人得到它是这样的:
mylist[X:Y]
X是您想要的第一个元素的索引.
Y是您不想要的第一个元素的索引.
Python切片表示法:
a[start:end:step]
对于start
和end
,负值被解释为相对于序列的末尾.
用于end
指示要包括的最后一个元素之后的位置的正指数.
空值默认如下:[+0:-0:1]
.
使用负一步反转的解释start
和end
符号扩展到(numpy)矩阵和多维数组.例如,要切片整列,您可以使用:
m[::,0:2:] ## slice the first two columns
切片保存数组元素的引用,而不是副本.如果要将数组单独复制,可以使用deepcopy()
.
您还可以使用切片分配从列表中删除一个或多个元素:
r = [1, 'blah', 9, 8, 2, 3, 4] >>> r[1:4] = [] >>> r [1, 2, 3, 4]
这就是我教给新手的切片的方法:
了解索引和切片之间的区别:
Wiki Python有这个令人惊叹的图片,清楚地区分索引和切片.
它是一个包含6个元素的列表.要更好地理解切片,请将该列表视为一组放在一起的六个框.每个方框都有一个字母.
索引就像处理框的内容一样.您可以查看任何框的内容.但是你不能一次检查多个盒子的内容.您甚至可以替换该框的内容.但你不能将2个球放在一个盒子里或一次更换2个球.
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)in () ----> 1 alpha[0,1] TypeError: list indices must be integers, not tuple
切片就像处理盒子一样.您可以先取出盒子并将其放在另一张桌子上.拾取盒子你需要知道的是盒子开始和结束的位置.
您甚至可以在1到4之间拾取前3个盒子或最后2个盒子或所有盒子.因此,如果您知道开始和结束,您可以选择任何一组盒子.这个位置称为开始和停止位置.
有趣的是,您可以一次更换多个盒子.您也可以在任何地方放置多个盒子.
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具有称为slice的内置函数,因此您可以传递一些参数并检查它计算缺失参数的巧妙程度.
In [21]: alpha = ['a', 'b', 'c', 'd', 'e', 'f'] In [22]: s = slice(None, None, None) In [23]: s Out[23]: slice(None, None, None) In [24]: s.indices(len(alpha)) Out[24]: (0, 6, 1) In [25]: range(*s.indices(len(alpha))) Out[25]: [0, 1, 2, 3, 4, 5] In [26]: s = slice(None, None, -1) In [27]: range(*s.indices(len(alpha))) Out[27]: [5, 4, 3, 2, 1, 0] In [28]: s = slice(None, 3, -1) In [29]: range(*s.indices(len(alpha))) Out[29]: [5, 4]
注意:这篇文章最初写在我的博客http://www.avilpage.com/2015/03/a-slice-of-python-intelligence-behind.html
这只是一些额外的信息......请考虑下面的列表
>>> 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]
请参阅上面的abc答案
作为一般规则,编写具有大量硬编码索引值的代码会导致可读性和维护混乱.例如,如果你在一年之后回到代码中,你会看到它并想知道你在编写代码时的想法.显示的解决方案只是一种更清楚地说明代码实际执行情况的方法.通常,内置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 >>>
为简单起见,请记住切片只有一种形式:
s[start:end:step]
以下是它的工作原理:
s
:可以切片的对象
start
:第一个开始迭代的索引
end
:last index,注意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
也可能是消极的!
否定步骤意味着向后迭代数组:从结束到开始,包括结束索引,并从结果中排除开始索引.
注意:当step为负数时,start
to 的默认值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)in () ----> 1 s[11] IndexError: list index out of range
上面的答案没有讨论使用着名的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"在逗号在第二个维度上运行后.
#!/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.
我的大脑似乎很乐意接受lst[start:end]
包含start
第 - 项的东西.我甚至可以说这是一种"自然假设".
但偶尔会有一个疑问,我的大脑要求保证它不包含end
-th元素.
在这些时刻,我依靠这个简单的定理:
for any n, lst = lst[:n] + lst[n:]
这个漂亮的属性告诉我,lst[start:end]
它不包含end
-th项,因为它在lst[end:]
.
请注意,这个定理对于任何一个n
都是正确的.例如,您可以检查
lst = range(10) lst[:-42] + lst[-42:] == lst
回报True
.
关于Slice符号,上述大多数答案都清楚了.用于切片的扩展索引语法是aList[start:stop:step]
基本示例
:
更多切片示例:15个扩展切片
在Python中,切片的最基本形式如下:
l
start
某些集合在哪里,end
是一个包含索引,l
是一个独有的索引.
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', '.', '.', '.']
where start
是一个集合,end
是一个包含索引,step
是一个独占索引,l
是一个可以用来取每个第n项的步幅step
.
l[start:end:step]
使用step
提供了一个有用的技巧来反转Python中的集合:
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
作为以下示例:
In [25]: l[::-1] Out[25]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
但是,使用负值start
可能会变得非常混乱.此外,为了Python化,应避免使用end
,step
以及l
在一个片.如果需要这样做,请考虑在两个分配中执行此操作(一个用于切片,另一个用于步长).
In[28]: l[::-2] Out[28]: [9, 7, 5, 3, 1]
我想添加一个Hello world示例,它解释了初学者的切片基础知识.这对我帮助很大.
让我们有一个包含六个值的列表['P', 'Y', 'T', 'H', 'O', 'N']
:
+---+---+---+---+---+---+ | P | Y | T | H | O | N | +---+---+---+---+---+---+ 0 1 2 3 4 5
现在,该列表中最简单的切片是其子列表.符号是[
,关键是这样读:
[ 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']
以下是字符串索引的示例
+---+---+---+---+---+ | 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-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
我认为,如果以以下方式(继续阅读)看待它,您将更好地理解和记住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]
。
这是该示例的可视化示例...
azString = "abcdefghijklmnopqrstuvwxyz"
因此,您要做的就是将index1和index2设置为所需子字符串周围的值。例如,要获取子字符串“ cdefgh”,可以使用azString[2:8]
,因为“ c”左侧的索引是2,而在“ h”右侧的索引是8。
请记住,我们正在设定界限。这些边界是您可以放置一些括号的位置,这些括号将像这样围绕子字符串...
ab [ cdefgh ] ij
该技巧始终有效,并且易于记忆。
如果您认为切片中的负索引令人困惑,这是一种很简单的思考方法:只需将替换为负索引len - index
。因此,例如,将-3替换为len(list) - 3
。
说明什么切片并在内部只是显示它的代码的最佳方式实现这一操作:
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 a for-loop with start, end and step return [list[i] for i in range(start, end, step)]