今天偷个懒,说个简单点的
切片作为日常基本操作,相信大家都不陌生,只不过可能对某些细节平时没有太多关注,这里就一起整理一下吧~
一、切片的对象
一般来说,切片的对象是序列,更通俗地说,就是我们常用的str, unicode, lict, tuple等
但仔细来说的话,其实应该是“实现了 ,使用数字索引,且索引是从0开始直到长度-1”的类,也就是实现了序列协议的类。
关于序列和序列协议,可参见我昨天的文章。python里默认的序列有这六种:
但这只说了一半,因为切片有两种操作,一种使用 ,另一种使用 。也就是
这里要提一个概念出来,叫做“可变序列”和“不可变序列”,就是说这个序列在创建后,是否允许修改,也就是是否实现了 方法。像str, unicode, tuple都是不可变,而list则是可变的。关于这个问题,可以去看下可变序列的文档: https://docs.python.org/2/library/collections.html#collections.MutableSequence 。或者去看看源码,python2的在这一行把list设置为了可变序列: https://github.com/python/cpython/blob/2.7/Lib/_abcoll.py#L695 。python3的在这里: https://github.com/python/cpython/blob/3.6/Lib/collections/abc.py 。
之后可以延伸到可变对象和不可变对象上,下次再说吧,这里只看切片
知道了这个之后,我们就也可以让自己定义的类支持切片了
需要注意,如果对字符串等不可变序列使用切片赋值操作,会报错:
二、切片的实现原理
我们知道,在使用 符号时取值时,会调用 函数,切片也正是依赖于此。
在切片操作 里,我们传进去的三个参数,都会被传给内置函数 ,这个函数里通过 和 来完成切片功能,但我们好像并不能直接使用slice函数,这里我没仔细看过。
三、切片的一些小笔记
切片赋值操作时,左侧原序列里指定的内容会被直接替换成右侧的内容,序列会自动进行收缩或扩张
如果start=0,或stop=sequence(obj),那么应将其留空,这可以让代码看起来清爽一些
当什么值都不传,使用 时,会将sequence完整复制一份返回,这里有个小小的点,看下面代码,a很符合我们的理解,但b和c为什么返回的跟之前相同呢?我一开始以为是常量池的问题,但后来将b和c搞的很大,发现也都跟之前一样,于是我觉得应该是“如果是不可变对象,则直接返回本身,如果是可变对象,再创建一个新的”,这里留待验证。
索引可以用负值,但与直接取下标相同,-0等价于0,因此 等价于
如果step是负值,那么最好不要在一次切片里同时指定start, stop和step,因为可能会非常难以阅读。可以拆成两句,先范围切割,再步进切割,缺点是多耗一截内存。对内存要求严格的话,可以考虑用itertools.islice,这里强制要求step使用正值(哈哈哈哈),原因见下一条
切片操作返回的是序列,可能会造成大量内存消耗,为了避免这一点,可以使用itertools.islice,这个函数接收可迭代对象,并且返回切片后的迭代器。也正是由于返回的是迭代器,只能正向循环,所以step不能是负值。很关键的一点是,接收的可迭代对象也可以是迭代器,也就是说islice可以对迭代器进行切片,这就很给力了
切片的一个好用的操作: 由于start和stop都没有索引越界问题,所以可以用切片来限制输入的长度,如 (不管输入多少内容都只取前20位)
numpy里的二维数组也支持切片,而且可以指定切行和列,就更好用了
问问各位,我写的这些有没有用啊,求个反馈
领取专属 10元无门槛券
私享最新 技术干货