我们来看一段代码,注意一下这里的start和end指的都是索引号,不是值(如[3:6]就是指索引号为3/4/5的元素,索引号从0开始):

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
# 模式[start:end:step]
"""
其中,第一个数字start表示切片开始位置,默认为0;
第二个数字end表示切片截止(但不包含)位置(默认为列表长度);
第三个数字step表示切片的步长(默认为1)。
当start为0时可以省略,当end为列表长度时可以省略,
当step为1时可以省略,并且省略步长时可以同时省略最后一个冒号。
另外,当step为负整数时,表示反向切片,这时start应该比end的值要大才行。
"""
aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
print (aList[::]) # 返回包含原列表中所有元素的新列表
print (aList[::-1]) # 返回包含原列表中所有元素的逆序列表
print (aList[::2]) # 隔一个取一个,获取偶数位置的元素
print (aList[1::2]) # 隔一个取一个,获取奇数位置的元素
print (aList[3:6]) # 指定切片的开始和结束位置
print(aList[0:100]) # 切片结束位置大于列表长度时,从列表尾部截断
print(aList[100:] ) # 切片开始位置大于列表长度时,返回空列表

# 输出结果:
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
[3, 5, 7, 11, 15]
[4, 6, 9, 13, 17]
[6, 7, 9]
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
[]

看完上面的我们再来看下面的,注意各步之间无任何关联,各步均和第一步产生反应:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]

aList[len(aList):] = [9] # 在列表尾部增加元素,[3, 4, 5, 6, 7, 9, 11, 13, 15, 17, 9]
aList[:0] = [1, 2] # 在列表头部插入元素,[1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
aList[3:3] = [4] # 在列表中间位置插入元素,[3, 4, 5, 4, 6, 7, 9, 11, 13, 15, 17]
aList[:3] = [1, 2] # 替换列表元素,等号两边的列表长度相等,[1, 2, 6, 7, 9, 11, 13, 15, 17]
aList[3:] = [4, 5, 6] # 等号两边的列表长度也可以不相等,[3, 4, 5, 4, 5, 6]
aList[::2] = [0] * 5 # 隔一个修改一个,[0] * 3 其实就是[0,0,0],
# 注意切片后的列表中元素的个数是否与待修改元素一致,[0, 4, 0, 6, 0, 9, 0, 13, 0, 17]

aList[::2] = ['a', 'b', 'c', 'd', 'e'] # 隔一个修改一个,运行结果如下
# ['a', 4, 'b', 6, 'c', 9, 'd', 13, 'e', 17]

aList[::2] = [1,2] # 左侧切片不连续,等号两边列表长度必须相等,这个运行会出错
aList[:3] = [] # 删除列表中前3个元素,[6, 7, 9, 11, 13, 15, 17]

del aList[:3] # 切片元素连续,[6, 7, 9, 11, 13, 15, 17]
del aList[::2] # 切片元素不连续,隔一个删一个,[4, 6, 9, 13, 17]

# 输出结果:

aList[::2] = [1,2] # 左侧切片不连续,等号两边列表长度必须相等,这个运行会出错
ValueError: attempt to assign sequence of size 2 to extended slice of size 5

我们来仔细看一下到底发生了什么:

1
2
3
4
5
6
7
8
9
10
11
12
aList = [1, 2, 4, 4, 5, 6]
aList[::2] = [0] * 3 # 隔一个修改一个,[0] * 3 其实就是[0,0,0]
print (aList)

aList[::2] = ['a', 'b', 'c'] # 隔一个修改一个
print(aList)

# 输出结果:

[0, 2, 0, 4, 0, 6]
['a', 2, 'b', 4, 'c', 6]

现在我们是需要自己来定义一个可以像列表那样的,支持各种切片处理的对象(我们实现一个不可变的对象)。我们查看源码,看这个Sequence里面包含了哪些魔法函数,我们先把里面的魔法函数都复制一遍:

1
from Lib import _collections_abc

将光标放在_collections_abc上面,然后按住Ctrl,单击鼠标左键就可以查看源码了:

1
2
3
4
5
6
7
8
9
10
__all__ = ["Awaitable", "Coroutine",
"AsyncIterable", "AsyncIterator", "AsyncGenerator",
"Hashable", "Iterable", "Iterator", "Generator", "Reversible",
"Sized", "Container", "Callable", "Collection",
"Set", "MutableSet",
"Mapping", "MutableMapping",
"MappingView", "KeysView", "ItemsView", "ValuesView",
"Sequence", "MutableSequence",
"ByteString",
]

然后我们类似操作选择点击Sequence,它就是不可变的,右边的MutableSequence就是可变的,其实就是在他的基础上进行了一些封装,功能多了而已。发现它实现了4个魔法函数,我们把它们写到Group里面:

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
class Group:
# 支持切片操作
def __init__(self, group_name, company_name, staffs):
self.group_name = group_name
self.company_name= company_name
self.staffs = staffs

def __getitem__(self, item):
return self.staffs[item]

def __iter__(self):
pass

def __contains__(self, item):
pass

def __reversed__(self):
pass


staffs = ["hello", "envse" , "lichee" ]
group = Group(group_name="kbthink", company_name="envse", staffs=staffs)
group[:2]

# 运行结果:
['hello', 'envse']

发现运行没有报错,说明它就已经支持我们的切片操作了,因为里面具有__getitem__()这个魔法函数。