楔子
本篇文章来探讨一下切片是如何实现的,因为在操作字符串、元组、列表等数据结构时,我们经常会使用切片截取数据,所以对切片做一个全方位的了解是很有必要的。
data = list(range(10))
print(data[1: 8: 3]) # [1, 4, 7]
以上就是基于切片截取数据,在工作中我们会大量使用切片。但你知道吗,其实切片也是一个对象,类型为 slice,下面我们来看一下切片的底层结构。
切片的底层结构
切片的类型是 slice,那么根据解释器的 API 命名规则,我们猜测:
切片(slice 对象)在底层对应 PySliceObject 结构体实例;
slice 类型本身在底层对应 PySlice_Type;
下面看一下具体实现。
// Include/sliceobject.h
typedef struct {
PyObject_HEAD
PyObject *start, *stop, *step;
} PySliceObject;
切片是不可变对象,除了对象的公共头部之外,还有三个字段,分别表示切片的起始位置、终止位置、步长。这也意味着创建切片时,可以给 slice 传递三个参数。
# 创建一个切片
s = slice(1, 8, 3)
print(s) # slice(1, 8, 3)
问题来了,切片创建的时候,传递的参数绑定在了哪些属性上呢?前面我们说过,实例对象可以绑定哪些属性,会定义在类型对象的 tp_members 字段中。
我们看到切片拥有三个属性,名称也是 start、stop、step。
s = slice(1, 8, 3)
print(s) # slice(1, 8, 3)
print(s.start) # 1
print(s.stop) # 8
print(s.step) # 3
非常简单,你在 Python 里面看到的一切,都能从源码中找到答案。
切片是怎么创建的
切片是内置类型的实例对象,对于这样的对象,有两种创建方式,相信你已经知道我要说什么了。我们在最开始专门用了十篇文章,从宏观的角度介绍了 Python 的对象模型,目的就在于此。