`
frank-liu
  • 浏览: 1684152 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

python slice的几个小点总结

 
阅读更多

问题的起因

    今天在写代码的时候,看到一个比较有意思的写法。假设我们有一个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[::2]
[0, 2, 4, 6, 8]
>>> l[1::2]
[1, 3, 5, 7, 9]
>>> 

    前面这种包含两个冒号的样式是怎么回事呢?

     实际上,我们这边第一个冒号隔开的这两个部分和前面的意思是一样的,就是指定数组中间元素的区间。所以前面第一个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的位置来确定方向,不要犯方向性的错误,否则就竹篮打水一场空了:)

分享到:
评论
3 楼 z1050334 2014-05-31  
frank-liu 写道
z1050334 写道
list = [x for x in range(10)];
list[:] ??等同于list[0:10]??
那list[::-1]等同于list[0:10:-1]???
求解

前面的代码里list=[x for x in range(10)] 其实就是返回一个列表,里面包含有元素0到9.所以在这种情况下list[:]表示的是整个list里的元素,而list[0:10]表示取的是索引从0到10的半开半闭区间[0, 10)。从0到10有11个,去掉后面那个不取,所以也是取了10个元素,在这个情况下他们两个是相等的。
而list[::-1]和list[0:10:-1]却不一样。因为我们在list[::-1]里就指定了默认的步长是-1,它默认的实现是从最后往前移动来取元素。所以得到的是结果[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]。 而list[0:10:-1]的时候相当于你指定了取元素的头和尾,0号元素是最前面的,10号是最后面的。但是我们从前面往后面取的话是需要+1的步长,这里我们设置的步长是-1,起点又是0。所以这里list[0:10:-1]会从0开始往另外一个方向取,得到的结果是[]。

明白了,最终都是Python的默认机制在捣鬼。
如果a和b都不填:
        步长为正,a为0,b为list长度
        步长为负,a为list长度,b为0
thanks
2 楼 frank-liu 2014-05-30  
z1050334 写道
list = [x for x in range(10)];
list[:] ??等同于list[0:10]??
那list[::-1]等同于list[0:10:-1]???
求解

前面的代码里list=[x for x in range(10)] 其实就是返回一个列表,里面包含有元素0到9.所以在这种情况下list[:]表示的是整个list里的元素,而list[0:10]表示取的是索引从0到10的半开半闭区间[0, 10)。从0到10有11个,去掉后面那个不取,所以也是取了10个元素,在这个情况下他们两个是相等的。
而list[::-1]和list[0:10:-1]却不一样。因为我们在list[::-1]里就指定了默认的步长是-1,它默认的实现是从最后往前移动来取元素。所以得到的是结果[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]。 而list[0:10:-1]的时候相当于你指定了取元素的头和尾,0号元素是最前面的,10号是最后面的。但是我们从前面往后面取的话是需要+1的步长,这里我们设置的步长是-1,起点又是0。所以这里list[0:10:-1]会从0开始往另外一个方向取,得到的结果是[]。
1 楼 z1050334 2014-05-30  
list = [x for x in range(10)];
list[:] ??等同于list[0:10]??
那list[::-1]等同于list[0:10:-1]???
求解

相关推荐

    128道Python面试题.pdf

    答:可以使用Python的字符串slice操作来反转字符串,使用"aStr"[::-1]语法。 列表操作知识点: 7. 将字符串 "k:1 |k1:2|k2:3|k3:4",处理成字典 {k:1,k1:2,...}? 答:可以使用Python的字符串split()函数来分割...

    python期末复习——python知识要点(csdn)————程序.pdf

    在Python的期末复习中,以下几个核心知识点是必须掌握的: 1. **Python语言特点与书写规范**: - Python是解释型语言,这意味着代码无需编译即可执行。 - 它是开源的,提供了一个广泛的社区支持和丰富的标准库。 ...

    Python 新手必会的 9 个 Python 教程.docx

    ### Python新手必会的9个Python教程知识点详解 #### 一、清理字符串输入 在编程过程中,特别是涉及用户输入的应用场景中,清理字符串是非常重要的一步。文档中提到了几种清理字符串的方法,包括基本的大小写转换、...

    核密度估计大作业KDE代码

    这个过程通常包括以下几个步骤: 1. 数据预处理:清洗和标准化输入数据。 2. 选择核函数:常见的核函数有高斯(Gaussian)、Epanechnikov、三角形等,它们影响估计的平滑程度。 3. 设置带宽(Bandwidth):控制核...

    mimics教程

    下面将详细介绍其中几个关键模块的功能: ##### 1. MEDCAD模块 MEDCAD模块作为医学影像数据与CAD之间的桥梁,提供了强大的双向交互能力,使得扫描数据与CAD数据之间的转换变得简单高效。具体来说: - **轮廓线...

    Slice-of-a-Pizza:那个美味的比萨中最神奇的一块。

    在这个项目中,我们可以期待学习到以下几个与Python和软件开发相关的知识点: 1. **面向对象编程(Object-Oriented Programming, OOP)**:披萨店和披萨本身都是现实世界中的对象,很可能会被抽象成Python类。通过...

    Wigner-Ville分布分布

    在MATLAB环境中,实现Wigner-Ville分布通常涉及以下几个步骤: 1. **信号预处理**:首先,你需要有一个实验数据集。这些数据可能来自于传感器测量、音频信号、图像处理或其他任何需要分析的信号源。确保数据是连续...

    Ice3.6.0 手册

    - **使用C#、Java、JavaScript、Objective-C、PHP、Python、Ruby和Visual Basic编写Ice应用**:同样地,也为其他几种语言提供了创建简单Ice应用的指南。 ### Slice语言详解 - **Slice编译**:介绍如何将Slice源...

    核密度估计大作业KDE

    在实现过程中,需要注意以下几个关键点: 1. 数据预处理:确保数据集是干净且无缺失值的。 2. 参数选择:核函数的带宽(或称为窗宽)对结果有很大影响。带宽太小可能导致过度拟合,而带宽太大则可能使细节丢失。通常...

    Siamese网络训练和预测guide

    - 使用了之前训练caffenet的脚本,说明了几个关键的参数设置。--resize_height和--resize_width参数用于调整图像大小,而--shuffle参数用于打乱数据集中的数据顺序,确保在训练过程中样本的随机性。文档中提到,...

    字符串截取小例子Delphi源代码..rar

    字符串截取通常涉及到以下几个关键知识点: 1. **字符串类型**:在Delphi中,字符串通常使用`string`类型表示,这是一个动态的Unicode字符串类型。它可以在运行时自动调整长度,非常灵活。 2. **Substring函数**:...

    医学图像处理DICOMM文件显示

    在“医学图像处理DICOMM文件显示”这个主题中,主要涉及到以下几个关键知识点: 1. **DICOM 文件结构**:DICOM 文件由一系列的数据元素(Data Elements)组成,每个元素包含一个标签(Tag)和相关数据。标签定义了...

    【JavaScript源代码】vue实现表格分页功能.docx

    总结起来,Vue.js实现表格分页功能主要涉及以下几个步骤: 1. 使用`el-table`组件展示数据,并利用`slice`方法按需加载当前页数据。 2. 使用`el-pagination`组件创建分页导航,并监听`current-change`和`size-change...

    project:上传测试

    在测试过程中,我们需要关注以下几个关键点: 1. **兼容性测试**:确保文件上传功能在各种浏览器和设备上都能正常工作,包括Chrome、Firefox、Safari、Edge以及移动设备。 2. **错误处理**:编写健壮的错误处理...

    【JavaScript源代码】JavaScript统计字符出现次数.docx

    这种方法不仅可以统计字符出现的次数,还可以根据字符出现的次数进行排序,并仅显示出现次数最多的前几个字符。步骤如下: 1. **定义类**:定义一个`Summary`类,包含两个属性`char`和`count`,分别表示字符及其...

    Django 1.0 Cheat Sheet

    ### Django 1.0 Cheat Sheet 知识点详解 #### 概述 "Django 1.0 Cheat Sheet" 是一份非常实用的参考资料,为开发者提供了关于 Django 1.0 版本中的各种模板标签和过滤器的快速查阅指南。这份文档涵盖了从基本的文本...

Global site tag (gtag.js) - Google Analytics