相信即使是Python新手也很容易理解下面的切片行为:

>>> s = 'this_is_a_test'
>>> s[1 : 5]
'his_'

进一步,下面的语法及输出也很不难理解:

>>> s = 'this_is_a_test'
>>> s[ : : 2]
'ti_sats'

那么,下面的呢?

>>> s = 'this_is_a_test'
>>> s[ : : -1]
'tset_a_si_siht'  ## 为何s被反转了?
>>> s[1 : 6 : -1]
''  ## 为何只得到个空串?
>>> s[6 : 1 : -1]
'si_si'  ## 为何是这个结果?

是不是觉得当slicing表达式的第3个参数(步长,"stride" or "step")为负数时,结果有点奇怪?
说实话,新手对上述结果感到困惑是正常的(当然,如果你完全搞明白了“为什么”,那么恭喜你,因为你对Python语法基础掌握的应该比较扎实了)。
本篇笔记就是要剖析slicing表达式的语法,争取为Python初学者解开上例的困惑。

1. 切片表达式(slicing expression)
Python官方文档对切片语法的说明非常简洁:
A slicing selects a range of items in a sequence object (e.g., a string, tuple or list). Slicings may be used as expressions or as targets in assignment or del statements.
根据文档说明,切片语法分为两种:简单切片(simple_slicing)扩展切片(extended_slicing),下面分别进行介绍。

2. 简单切片(simple_slicing)
简单切片语法如下:
s[begin : end]
其中,s表示任何sequence类型的对象,begin和end必须是int值或求值后可以得到int值的表达式,它们及其之间的分号共同构成了一个前闭后开区间(即begin <= idx < end),指明切片操作将要访问的源序列s的索引值的begin和end,其中真正的end位置是s中end的前一个位置,也即,切片返回的序列的最后一个element在源序列s的索引为(end-1)。
备注1:begin和end都可以被缺省,此时,它们的默认值分别是0和sys.maxint
备注2:begin和end的值可以超过序列的实际长度,如s = [1, 2, 3]; s[0 : 8]也是合法的
备注3:begin和end均可以为负值。按照Python解释器内部实现的约定,-1是序列s最后一个元素的索引,-2是倒数第二个元素的索引,以此类推。我们可以借助Python官方教程strings说明文档关于slice的部分来理解正/负索引号的对应关系(注意,下面的示意图对原文档中索引值画的位置有所微调,个人认为这样更易于大多数人的理解):

由上图可知,Python内部表示sequence类型时,若采用正索引值表示,则有效的索引范围是[0, len(s)-1];若采用负索引值表示,则有效的索引范围是[-len(s), -1]
如果能牢牢记住这一点,那关于slice的一些看起来让人疑惑的语法行为就比较容易理解了。
下面的slicing表达式均属于简单切片语法:

>>> s = ['a', 'b', 'c', 'd', 'e', 'f']
>>> s[0 : len(s)] ## output: ['a', 'b', 'c', 'd', 'e', 'f']
>>> s[0 : -1]     ## output: ['a', 'b', 'c', 'd', 'e']
>>> s[ : -1]      ## output: ['a', 'b', 'c', 'd', 'e']
>>> s[2 : -1]     ## output: ['c', 'd', 'e']
>>> s[-3 : -1]    ## output: ['d', 'e']
>>> s[-3 : ]      ## output: ['d', 'e', 'f']
>>> s[3 : 1]      ## output: []

3. 扩展切片(extended_slicing)
扩展切片语法如下:
s[begin : end : stride]
与简单切片语法相比,扩展切片只是增加了第3个参数,即步长参数(英文资料中通常称为"stride"或"step")。
扩展切片语法引入的"stride"参数是个需要特别注意的参数,因为它的正/负取值将会影响切片操作对源序列s的访问方向,而这正是本文开始那几个示例可能引起Python新手困惑的原因。
其实规则很简单,说穿不值一文钱:
1) 当stride参数为正值(positive)时,表明切片操作从左至右(即正向)访问源序列s的元素,此时,若begin和end参数有缺省,则Python解释器默认将其设置为None。如s[0 : : 1]会被解释器当作s[0 : None : 1],此时,end实际取值要大于其有效索引范围的上限值,以保证切片操作能访问到源序列s从begin开始的所有元素(从左向右)。
2) 当stride参数为负值(negative)时,表明切片操作从右至左(即逆向)访问源序列s的元素,此时,若begin和end参数有缺省,则Python解释器默认将其设置为None。如s[-1 : : -1]会被解释器当作s[-1 : None : -1],此时,end实际取值要小于其有效索引范围的下限值,已保证切片操作能访问到源序列s从begin开始的所有元素(逆向,从右向左)。
3) 无论stride参数取正值还是负值,切片表达式的begin和end索引值需要保证在切片操作的访问方向上,从begin到end之间有元素,这样切片操作才能保证返回非空集。
通过本文第2节给出的Python内部对序列对象索引值约定示意图,应该可以很容易地理解这3条规则。
介绍到这里,本文开始处的那个示例输出结果的原因想必也很清楚了吧。

>>> s = 'this_is_a_test'
>>> s[ : : -1]
'tset_a_si_siht'  ## Q: 为何s被反转了? A: 步长参数-1表明逆向访问s
>>> s[1 : 6 : -1]
''  ## Q: 为何只得到个空串? A: 步长参数为负时,逆向访问,但begin与end间无元素,故返空串
>>> s[6 : 1 : -1]
'si_si'  ## Q: 为何是这个结果? A: 逆向访问,切片访问到的元素正值索引范围为[2:6],故返'si_si'

备注:根据《Python核心编程》一书第6.1.2节的介绍,这里称为“扩展”是因为早期的Python解释器只支持不带步长参数的简单切片,带步长的切片操作是以Python扩展的方式实现的。事实上,目前的CPython解释器早就支持纯Python的带步长参数的切片操作,但作为历史名称,“扩展”一词被保留下来。

【参考资料】
1. Python Docs: slicings  
2. Python Docs: An Informal Introduction to Python - strings 
3. Section 6.1.2 & 6.3.2 of <Core Python Programming>,即《Python核心编程》一书第6.1.2节和6.3.2节
4. StackOverflow: Explain Python's slice notation

========================= EOF ======================

【Python笔记】剖析Python的切片(slicing)语法相关推荐

  1. python 网页版笔记_【Python笔记】Python网页正文抽取工具

    本文信息本文由方法SEO顾问发表于2016-05-2018:48:27,共 1153 字,转载请注明:[Python笔记]Python网页正文抽取工具_[方法SEO顾问],如果我网站的文章对你有所帮助 ...

  2. python笔记基础-Python入门基础知识学习笔记之一

    为什么要写这篇文章? 本人做过Objective-C开发,现在在用C#做WinForm开发.近段时间在学习Python入门基础知识时,发现有很多知识点和Objective-C的不一样.故想通过本文记录 ...

  3. python笔记基础-python学习笔记(一)python简介和基础

    1.什么是python? python是一种面向对象的,解释型的计算机语言,它的特点是语法简介,优雅,简单易学.1989年诞生,Guido(龟叔)开发. 编译型语言:代码在编译之后,编译成2进制的文件 ...

  4. 廖雪峰python笔记1 python简介

    廖雪峰python笔记 是自己根据廖雪峰的python教程做的一点笔记 1 python简介 1 python简介 廖雪峰python笔记 1.1 python是解释性语言 1.2 Python适合开 ...

  5. python笔记基础-python基础学习笔记(一)

    安装与运行交互式解释器 在绝大多数linux和 UNIX系统安装中(包括Mac OS X),Python的解释器就已经存在了.我们可以在提示符下输入python命令进行验证(作者环境ubuntu) f ...

  6. 【python笔记】python模块 datatime模块

    模块 使用" import xxx module "导入模块的本质就是: 将xxxmodule .py 中的全部代码加载到内存井执行,然后将整个模块内容赋值给与模块同名的变量,该变 ...

  7. 【python笔记】python基础(注释,缩进,变量,表达式,运算符)

    目录 python注释: python设计风格: 缩进: python程序的基本要素: 变量: 表达式: python运算符: python注释: #作为单行注释的开始标记 '''对多行注释 pyth ...

  8. 小甲鱼零基础学python笔记 P20 python变量简单了解

    P20 python变量: python默认是不会有返回值样例如下: 先给hello变量赋值,这里选择的是打印print 通过传递变量的将temp=hell()变量后只会返回默认值 需要使用参数ret ...

  9. python笔记基础-Python学习笔记(基础)

    python基础学习笔记.语法.函数等. 基础定义utf-8文件头#!/usr/bin/env python3 # -*- coding: utf-8 -*- 2.循环// name是值 names是 ...

  10. 学会Python真的有高收入?「python笔记」Python对象

    1. Python对象 Python使用对象模型来存储数据.构造任何类型的值都是一个对象. 所有的Python对象都拥有三个特性:身份,类型和值. 身份: 每一个对象都有一个唯一的身份标识自己,任何对 ...

最新文章

  1. java ognl 性能_OGNL详解
  2. 利用C#语言实现小闹钟
  3. 1月31日云栖精选夜读:阿里云客户案例研究:罗辑思维
  4. 传输层TCP/UDP协议
  5. linux普通用户开不了端口,Linux中如何让普通用户使用小于1024的端口
  6. stm32L0工程建立(HAL+IAR,无cubemx)
  7. 编写一个判断素数的函数,在主函数输入一个整数时,输出是否素数的信息。...
  8. java put set_Java PutItemRequest.setItem方法代码示例
  9. C语言中输入输出fread和fwrite函数的用法
  10. InfluxDb系列:几个关键概念(主要是和关系数据库做对比)
  11. poj 2262 Goldbach's Conjecture——筛质数(水!)
  12. Ubuntu配置Typora和picgo
  13. 《信息安全工程》读书笔记
  14. ubuntu xampp进入mysql安全模式
  15. 「干货分享」50人+团队常用的一套PRD模板
  16. c语言论坛编程,[原创]了解c语言
  17. [DirectX 9.0笔记]第二章 渲染管线
  18. 论文阅读-MLPD:Multi-Label Pedestrian Detector in Multispectral Domain(海康威视研究院实习项目)
  19. 安装目录里无法找到计算机,安装软件弹出系统找不到指定的路径提示解决方法...
  20. thinkphp5整合系列之汉字转拼音完美支持多音字

热门文章

  1. python爬虫-代理池的维护
  2. 【Bug】Microsoft Edge拒绝访问
  3. 重构之前的数据统计,用于数据归档,要考虑数据迁移
  4. 机器学习(十)——支持向量机
  5. CPU使用率100%,如何解决
  6. 【ENOVIA】MBOM经理概述 | 达索系统百世慧®
  7. 对音频信号作短时傅里叶变换(STFT)/小波变换处理(python + matlab)
  8. Excel如何取消合并单元格并填充空单元格
  9. 私藏了好几年的20个谷歌搜索技巧
  10. android 5.0 n,EMUI 5.0遭泄漏 基于Android N制作!华为P9用户有福啦