Python includes syntax for slicing sequences into pieces. Slicing allows you to access a subset of a sequence’s items with minimal effort. The simplest uses for slicing are the built-in types list, str, and bytes. Slicing can be extended to any Python class that implements the __getitem__ and __setitem__ special methods (see Item 43: “Inherit from collections.abc for Custom Container Types”).
Python包含将序列切片的语法。切片允许您以最小的努力访问序列项的子集。切片最简单的用法是Python的内置类型list、str和bytes。切片也可以扩展到任何实现了__getitem__和__setitem__魔术方法的Python类型(参见第43项:“继承collections.abc自定义容器类型”)。
The basic form of the slicing syntax is somelist [start:end], where start is inclusive and end is exclusive:
切片语法的基本形式是somelist [start:end],其中start是包含的,end是不包含的:
a = [ 'a ', 'b ', 'c ', 'd ', 'e ', 'f ', 'g ', 'h ']
print ( 'Middle two: ', a [3:5])
print ( 'All but ends: ', a [1:7])
>>>
Middle two: [ 'd ', 'e ']
All but ends: [ 'b ', 'c ', 'd ', 'e ', 'f ', 'g ']
When slicing from the start of a list, you should leave out the zero index to reduce visual noise:
当从列表的开始位置切片时,你应该省略索引0以减少视觉干扰:
assert a [:5] == a [0:5]
When slicing to the end of a list, you should leave out the final index because it’s redundant:
当切片到列表的末尾时,你应该省略最终索引,因为它是冗余的:
assert a [5:] == a [5:len (a)]
Using negative numbers for slicing is helpful for doing offsets relative to the end of a list. All of these forms of slicing would be clear to a new reader of your code:
在切片时使用负数索引有助于做相对于列表末尾的偏移量。所有这些形式的切片对于你的代码的新读者来说都是清楚的:
a[:] # ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
a[:5] # ['a', 'b', 'c', 'd', 'e']
a[:-1] # ['a', 'b', 'c', 'd', 'e', 'f', 'g']
a[4:] # ['e', 'f', 'g', 'h']
a[-3:] # ['f', 'g', 'h']
a[2:5] # ['c', 'd', 'e']
a[2:-1] # ['c', 'd', 'e', 'f', 'g']
a[-3:-1] # ['f', 'g']
There are no surprises here, and I encourage you to use these variations. Slicing deals properly with start and end indexes that are beyond the boundaries of a list by silently omitting missing items. This behavior makes it easy for your code to establish a maximum length to consider for an input sequence:
这没有什么惊讶的,我鼓励您使用这些变体。切片通过默认省略缺失项的方式,正确地处理超出列表边界的开始和结束索引。这种行为使得你的代码很容易为输入序列建立一个最大长度:
first_twenty_items = a [:20]
last_twenty_items = a [-20:]
In contrast, accessing the same index directly causes an exception:
相反,直接访问相同的索引将会导致异常:
a [20]
>>>
Traceback ...
IndexError: list index out of range
Note
注意
Beware that indexing a list by a negated variable is one of the few situations in which you can get surprising results from slicing. For example, the expression somelist [-n:] will work fine when n is greater than one (e.g., somelist[-3:]).However, when n is zero, the expression somelist [-0:] is equivalent to somelist [:] and will result in a copy of the original list.
请注意,用一个负变量对列表进行索引,可以从切片中得到令人惊讶的结果,这是几种少数情况之一。例如,表达式somelist[-n:]在n大于1时可以正常工作(例如,somelist[-3:])。但是,当n为0时,表达式somelist[-0:]等价于somelist[:],他会得到一个原始列表的副本。
The result of slicing a list is a whole new list. References to the objects from the original list are maintained. Modifying the result of slicing won’t affect the original list:
一个列表的切片结果是一个全新的列表。原始列表中的对象引用保持不变,修改切片结果不会影响到原始列表:
b = a [3:]
print ( 'Before: ', b)
b [1] = 99
print ( 'After: ', b)
print ( 'No change: ', a)
>>>
Before: [ 'd ', 'e ', 'f ', 'g ', 'h ']
After: [ 'd ', 99, 'f ', 'g ', 'h ']
No change: [ 'a ', 'b ', 'c ', 'd ', 'e ', 'f ', 'g ', 'h ']
When used in assignments, slices replace the specified range in the original list. Unlike unpacking assignments (such as a, b = c [:2]; see Item 6: “Prefer Multiple Assignment Unpacking Over Indexing”), the lengths of slice assignments don’t need to be the same. The values before and after the assigned slice will be preserved. Here, the list shrinks because the replacement list is shorter than the specified slice:
在赋值中使用时,切片将替换原始列表中的指定范围。不像解包赋值(比如a, b = c [:2];参见Item 6:“Prefer Multiple Assignment Unpacking Over Indexing”),切片赋值的长度不需要相同。切片之前和之后的值将被保留。在这里,列表收缩是因为替换列表比指定的切片短:
print ( 'Before ', a)
a [2:7] = [99, 22, 14]
print ( 'After ', a)
>>>
Before [ 'a ', 'b ', 'c ', 'd ', 'e ', 'f ', 'g ', 'h ']
After [ 'a ', 'b ', 99, 22, 14, 'h ']
And here the list grows because the assigned list is longer than the specific slice:
这里列表会增长,因为已赋值的列表比指定的切片长:
print ( 'Before ', a)
a [2:3] = [47, 11]
print ( 'After ', a)
>>>
Before [ 'a ', 'b ', 99, 22, 14, 'h ']
After [ 'a ', 'b ', 47, 11, 22, 14, 'h ']
If you leave out both the start and the end indexes when slicing, you end up with a copy of the original list:
如果你在切片时同时省去了开始和结束索引,你最终会得到一个原始列表的副本:
b = a [:]
assert b == a and b is not a
If you assign to a slice with no start or end indexes, you replace the entire contents of the list with a copy of what’s referenced (instead of allocating a new list) :
如果你给一个没有开始或结束索引的切片进行赋值,你就会得到整个列表的一个引用副本(而不是分配一个新的列表):
b = a
print ( 'Before a ', a)
print ( 'Before b ', b)
a [:] = [101, 102, 103]
assert a is b
print ( 'After a ', a)
print ( 'After b ', b)
>>>
Before a [ 'a ', 'b ', 47, 11, 22, 14, 'h ']
Before b [ 'a ', 'b ', 47, 11, 22, 14, 'h ']
After a [101, 102, 103]
After b [101, 102, 103]
Things to Remember
要记住的事
✦ Avoid being verbose when slicing: Don’t supply 0 for the start index or the length of the sequence for the end index.
✦ Slicing is forgiving of start or end indexes that are out of bounds, which means it’s easy to express slices on the front or back boundaries of a sequence (like a
[:20] or a[-20:]).
✦ Assigning to a list slice replaces that range in the original sequence with what’s referenced even if the lengths are different.
✦ 在切片时避免冗长:不要提供开始索引0,不要为结束索引提供列表的长度。
✦ 切片允许开始或结束索引超出边界,这意味着它很容易在序列的前面边界(例如a[:20])或序列的后面边界(例如a[-20:])上表示切片。
✦ 给一个列表的切片赋值,即使长度不同,也可以将原始序列中的范围替换为所引用的范围。