python每日一类(4):slice
class slice(stop)class slice(start, stop[, step])
Return a slice object representing the set of indices specified by range(start, stop, step). The start and step arguments default to None. Slice objects have read-only data attributes start, stop and step which merely return the argument values (or their default). They have no other explicit functionality; however they are used by Numerical Python and other third party extensions. Slice objects are also generated when extended indexing syntax is used. For example: a[start:stop:step] or a[start:stop, i]. See itertools.islice() for an alternate version that returns an iterator.
问题的起因
今天在写代码的时候,看到一个比较有意思的写法。假设我们有一个list,它的内容是a = [0, 1, 2, 3, 4, 5, 6, 7, 8 ,9]。如果我们取它反转后的结果,一般我们头脑里默认想到的无非就是reverse这样的方法了。但是它还有一种写法:a[::-1],输出的结果是和当前的结果相反。在某些情况下,它的应用还是比较有意思的。就想针对这一块总结一下。
slice在python中的应用
在Python中,list, tuple以及字符串等可以遍历访问的类型都可以应用slice访问。slice本身的意思是指切片,在这些可以遍历访问的类型中截取其中的某些部分。比如如下的代码:
>>> l = range(10)
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l[1:5]
[1, 2, 3, 4]
首先,我们通过range(10) 生成一个从0到9的列表。在这个列表中取[1:5]的时候返回的是索引1到4的。所以,我们发现他们所取的slice是一个半开半闭的区间。l[a:b]==> l[a, b).
前面这种情况下,是我们已知列表的长度,然后取他们的某个区段,如果我们不知道列表的长度,或者列表长度的获取比较麻烦呢?如果用其他的语言,我们可能考虑这个列表是否应该有一个list.length之类的属性了。在这里,有另外一个办法来取得:
>>> l[-1]
9
>>> l[1:-1]
[1, 2, 3, 4, 5, 6, 7, 8]
>>> l[2:-2]
[2, 3, 4, 5, 6, 7]
我们可以看到如果要取列表中的最后一个元素,可以用l[-1]的方式,如果从后面向前,可以依次取l[-2], l[-3]...
既然我们前面提到,在列表中slice是取的一个前面闭合后面开放的区间,也就是说我在l[a:b]的时候,索引值为b的那个元素是不包含在结果中的。如果我们想要包含后面的值那么该怎么办呢?
这个问题可以分为几种情况来考虑,一个是加入b本身长度比较小,那么我们取l[a:b+1]就好了。比如说如下:
>>> l[1:3]
[1, 2]
>>> l[1:4]
[1, 2, 3]
如果我们想把索引值为3的也包含进来,我们就用l[1:4]就行了。那么,对于处在列表末尾的元素呢?用过c, Java开发的人会想到,按照这种方式会不会导致访问数组越界呢?我们试试看吧:
>>> len(l)
10
>>> l[1:10]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l[1:11]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l[1:12]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
len(l)返回l的长度。我们原来潜意识的认为,既然数组长度为10,那么我们访问的索引最大值也不过为l[9]。实际上,在python这里,可以列出的访问下标值超出数组长度范围,只不过仅仅返回能遍历到的元素而已。
当然,我们还有另外一种办法:
>>> l[1:]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
这种方式就完全将前面索引到数组末尾的元素都包含进来了。
这样,我们要包含整个数组中的元素就可以采用如下的几种方式:
>>> l[0:]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l[:]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
从前面我们用l[a:b] 的方式来访问元素来看,我们这里a, b取的值要么满足0<= a <= b 或者 a >= 0 b < 0。实际上,a所对应元素的位置总是在b所对应位置的后面。那么,如果我们把他们的顺序倒过来一下会怎么样呢?比如说:
>>> l[5:2]
[]
>>> l[-1:3]
[]
在这里,我们发现,如果实际取的元素先从右边开始然后到左边的话,并不是我们所期望的返回一个倒过来的数组,而是返回一个空的数组。我举的这个例子有什么用呢?别急,看了后面那一节你就知道了。
理解extended slice
前面那一部分相对来说还是比较好理解的。现在,如果我们有一些其他的要求,比如说,我们想返回数组里面索引为奇数的元素,或者索引为偶数的元素,那么该怎么办呢?
我们可以有几种办法来做,其中的一种就是采用extended slice,一个典型的解决方法如下:
>>> l[::]
[, , , , ]
>>> l[::]
[, , , , ]
>>>
前面这种包含两个冒号的样式是怎么回事呢?
实际上,我们这边第一个冒号隔开的这两个部分和前面的意思是一样的,就是指定数组中间元素的区间。所以前面第一个l[::2]前面就是指的整个数组的元素。而后面那个部分则是指的一个步长。这表示什么意思呢?就是既然我们前面指定的是整个数组,那么它就是从0开始,然后每次访问后面相邻的元素。而设置为2之后呢,则访问后面和它距离为2的元素,而不是直接相邻的元素。这样,我们也就容易理解l[1::2],它就是从元素1开始到结尾的元素集合里取间隔为2的这些元素。
到这一步,就离我们理解前面那个古怪的l[::-1]很接近了。我们前面的这个取步长是将步长设置为正数,所以在取元素的集合里它表示从左到右的取指定步长覆盖的元素。如果我们将步长设置为负数呢?我们来看:
>>> l[1:9:-1]
[]
>>> l[9:1:-1]
[9, 8, 7, 6, 5, 4, 3, 2]
有了前面这一部分的代码,相信就不难理解了。我们取区间[1, 9),结果取步长为-1的时候返回的是一个空的集合。而我们取9到1的时候,步长为-1取出来了倒序的数组。这是因为如果我们指定的步长为负数的话,那么它必须和数据指定的区间方向一致。也就是说,如果我们前面指定的区间是从数组小的索引到大的索引,那么我指定的步长必然也要从小到大。所以必须为正数。而如果我们指定的区间是从后面往前的话,则步长必须指定为负数。否则返回的结果都是空的数组。
总结
有了前面那么多的讨论,我们再来看数组的slice访问。他们无非就是这么几个情况,在l[a:b]的情况下,必须保证a所在的索引位置在前,b所在的索引位置在后,否则返回结果为空。在l[a:b:step]的情况下,我们首先要根据a, b的位置来判断方向,a在前,b在后的话,step应该为正,否则应该为负。不符合这些情况的话,则返回空的数组。也就是说,看a, b的位置来确定方向,不要犯方向性的错误,否则就竹篮打水一场空了:)
python每日一类(4):slice的更多相关文章
- python每日一类(3):os和sys
os与sys模块的官方解释如下: os: This module provides a portable way of using operating system dependent functio ...
- python每日一类(2):platform
根据官方文档的解释(https://docs.python.org/3.5/library/platform.html#module-platform): 学习其他人的代码如下: # python p ...
- python每日一类(1):pathlib
每天学习一个python的类(大多数都是第三方的),聚沙成金. -------------------------------------------------------------------- ...
- python每日一类(5):itertools模块
itertools模块包含创建有效迭代器的函数,可以用各种方式对数据进行循环操作,此模块中的所有函数返回的迭代器都可以与for循环语句以及其他包含迭代器(如生成器和生成器表达式)的函数联合使用. ch ...
- Python每日一练(1):计算文件夹内各个文章中出现次数最多的单词
#coding:utf-8 import os,re path = 'test' files = os.listdir(path) def count_word(words): dic = {} ma ...
- 在python&numpy中切片(slice)
在python&numpy中切片(slice) 上文说到了,词频的统计在数据挖掘中使用的频率很高,而切片的操作同样是如此.在从文本文件或数据库中读取数据后,需要对数据进行预处理的操作.此时就 ...
- python每日一函数 - divmod数字处理函数
python每日一函数 - divmod数字处理函数 divmod(a,b)函数 中文说明: divmod(a,b)方法返回的是a//b(除法取整)以及a对b的余数 返回结果类型为tuple 参数: ...
- python中index、slice与slice assignment用法
python中index.slice与slice assignment用法 一.index与slice的定义: index用于枚举list中的元素(Indexes enumerate the elem ...
- python每日一练:0007题
第 0007 题: 有个目录,里面是你自己写过的程序,统计一下你写过多少行代码.包括空行和注释,但是要分别列出来. # -*- coding:utf-8 -*- import os def count ...
随机推荐
- java练习题——数组
上述代码可以顺利通过编译,并且输出一个“很奇怪”的结果:[Ljava.lang.Object;@2a139a55 为什么会出现这种情况? 直接输出object的对象,系统会输出地址,如果想要输出其中的 ...
- 亲手搭建一个基于Asp.Net WebApi的项目基础框架1
目标:教大家搭建一个简易的前后端分离的项目框架. 目录: 1:关于项目架构的概念 2:前后端分离的开发模式 3:搭建框架的各个部分 这段时间比较闲,所以想把之前项目里用到的一些技术写到博客里来,分享给 ...
- Hadoop学习笔记系列
Hadoop学习笔记系列 一.为何要学习Hadoop? 这是一个信息爆炸的时代.经过数十年的积累,很多企业都聚集了大量的数据.这些数据也是企业的核心财富之一,怎样从累积的数据里寻找价值,变废为宝炼 ...
- grunt简记
grunt和gulp都是前端自动化的工具,grunt更成熟,插件社区全.大:gulp比较年轻,性能更好,更简单容易.具体使用哪种可根据实际项目组来决定. 创建任务 grunt默认执行的是default ...
- USACO Section2.1 Healthy Holsteins 解题报告 【icedream61】
holstein解题报告 --------------------------------------------------------------------------------------- ...
- 如何自己编译apue.3e中代码 & 学习写makefile
本来是搜pthread的相关资料,看blog发现很多linux程序员都看的一本神书<APUE>,里面有系统的两章内容专门讲pthread(不过是用c语言做的代码示例,这个不碍事,还是归到原 ...
- spring 笔记2:Spring MVC : Did not find handler method for 问题的解决
日志显示为: Looking up handler method for path /***Did not find handler method for [/***]No mapping found ...
- 自动using和Layout
一.自动using 1. Model 文件夹添加 Person类,在view文件夹下web.config文件,将namespace加入,cshtml文件就不需要添加@model引用: ...
- IntelliJ IDEA 注释模版 输入/**后 不显示配置好的模板
简单一句话就是 当你在live templetes里配置好以后,记住abbreviation:输入框里的字母 比如我的是cc ,我要想写注释怎么办? 在方法上输入 /*cc 然后按tab键就出来了
- Android使用adb命令查看CPU信息
Android中使用JNI编程的时候会需要编译出不同的SO文件,以供适配不同的机型. 例如: 由此需要查看不同机型的CPU信息. 使用ADB命令查看CPU信息命令如下: 1. adb shell 2. ...