购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.1 通用序列操作

在讲解列表和元组之前,本节先介绍Python中序列的通用操作,这些操作在列表和元组中都会用到。

Python中所有序列都可以进行一些特定操作,包括索引(indexing)、分片(slicing)、序列相加(adding)、乘法(multiplying)、成员资格、长度、最小值和最大值。

3.1.1 索引

序列是Python中最基本的数据结构。序列中的每个元素都分配一个数字,代表它在序列中的位置(索引),第一个索引是0,第二个索引是1,以此类推。

序列中所有元素都是有编号的,从0开始递增。可以通过编号分别对序列的元素进行访问。下面通过交互输入方式介绍一个通过编号取元素的例子。

>>> greeting='Hello'#定义变量greeting,并赋值Hello
>>> greeting[0] #根据编号取元素,使用格式为:在中括号中输入所取元素的编号值
'H'
>>> greeting[1]
'e'
>>> greeting[2]
'l'

可以看到,序列中的元素从0开始,从左向右依自然顺序编号,元素可以通过编号访问。获取元素的方式为:在变量后加中括号,在中括号中输入所取元素的编号值。这个格式需要记住。

类似于我们平时排队,站成一排时,一般从左往右编号,编上序号后(一般从1开始编号,不会从0开始),当叫一个序号时,就会由序号对应到人。程序中的序列也是如此。

这里的编号就是索引,可以通过索引获取元素。所有序列都可以通过这种方式进行索引。

字符串是由字符组成的序列。索引0指向第一个元素。比如在上面的示例中,索引0指向字母H,索引1指向字母e,索引2指向字母l。

上面的示例是从左往右通过编号获取元素的,是否可以从右往左通过编号获取元素呢?我们试一试,在交互模式下输入:

>>> greeting[-1]
'o'
>>> greeting[-2]
'l'
>>> greeting[-3]
'l'
>>> greeting[-4]
'e'

可以看到,Python的序列也可以从右开始索引,最右边的元素索引值为-1,从右向左递减。

在Python中,从左向右索引称为正数索引,从右向左索引称为负数索引。使用负数索引时,Python会从最后一个元素开始计数。最后一个元素的位置编号是-1。

最后一个元素的编号不是-0,跟数学中的概念一样,-0=0、-0和0都指向第一个元素。

从上面的几个示例可以看到,进行字符串的索引时都定义了一个变量,其实不定义变量也可以。下面来看一个例子,在交互模式输入:

>>> 'Hello'[0]
'H'
>>> 'Hello'[1]
'e'
>>> 'Hello'[-1]
'o'
>>> 'Hello'[-2]
'l'

可以看到,直接使用索引,不定义变量进行引用也可以。直接使用索引的效果和定义变量的效果是一样的。

如果函数返回一个序列,是否可以直接对结果进行索引操作呢?在交互模式下输入:

>>> thirdth=input()[0]
happy
>>> thirdth
'h'

由输出结果可以看到,直接对函数的返回结果进行了索引操作。

索引既可以对变量的引用操作,也可以直接操作序列,还可以操作函数的返回序列。

3.1.2 分片

索引用来对单个元素进行访问,使用分片可以对一定范围内的元素进行访问,分片通过冒号相隔的两个索引实现。在交互模式输入:

>>> number=[1,2,3,4,5,6,7,8,9,10]
>>> number[1:3]      #取索引为第一和第二的元素
[2, 3]
>>> number[-3:-1]    #负数表明从右开始计数,取得倒数第三和倒数第二的元素
[8, 9]

由操作结果可以看到,分片操作既支持正数索引,也支持负数索引,并且对于提取序列的一部分很方便。

分片操作的实现需要提供两个索引作为边界,第一个索引的元素包含在分片内,第二个索引的元素不包含在分片内。像数学里的a≤x<b,x是我们需要得到的元素,a是分片操作中的第一个索引,b是第二个索引,b不包含在x的范围内。

对于上面的示例,假设需要访问最后3个元素,使用正数索引可以这样操作:

>>> number=[1,2,3,4,5,6,7,8,9,10]
>>> number[7:10] #取最后3 个元素
[8, 9, 10]

由以上输入和我们前面对序列的定义可以得出,number的编号最大应该为9,编号为10指向的是第11个元素,是一个不存在的元素,但是由于在最后一个元素之后,因此能得到最后一个元素。这么做没问题。如果需要从列表的结尾开始,即使用负数索引,怎么办呢?我们尝试看看,输入如下:

>>> number=[1,2,3,4,5,6,7,8,9,10]
>>> number[-3,-1]
[8, 9]

结果没有输出最后一个元素。再试试使用索引0作为最后一个元素的下一个元素,输入如下:

>>> number[-3:0]
 []

这个输出结果有点奇怪,竟然一个数值都没有。

事实上,只要在分片中最左边的索引比它右边的索引晚出现在序列中,结果就是一个空序列。比如上例中,-3代表倒数第3个元素,0代表第一个元素,倒数第3个元素比第一个元素晚出现,即排在第一个元素后面,所以得到的结果是空序列。

我们怎么通过负数索引的方式取得最后一个元素呢?这里有一个捷径可以使用。如果需要取得的分片包括序列结尾的元素,只需将第二个索引设置为空即可。输入如下:

>>> number[-3:]
 [8, 9, 10]

输出结果和我们预期的一样。

正数索引能否使用这种方式呢?输入如下:

>>> number[0:]  #从第一个元素开始输出,输出全部结果
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> number[:0] #最后一个元素为第一个,输出为空
[]
>>> number[:3] #取得前3 个元素
[1, 2, 3]

由输出结果可以知道也适用于正数索引。

根据上述输出结果可知,若需要输出整个序列,则可以将两个索引都设置为空。输入如下:

>>> number[:]  #取得整个数组
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

输出结果是整个序列。

进行分片时,分片的开始和结束点都需要指定(无论是直接还是间接),用这种方式取连续的元素没有问题,但若要取序列中不连续的元素就比较麻烦,或者直接不能操作。比如要取序列number中的所有奇数,以一个序列展示出来,用前面的方法就不能实现了。

对于上面这种情况,Python为我们提供了另一个参数——步长(step length),该参数通常是隐式设置的。在普通分片中,步长是1。分片操作就是按照这个步长逐个遍历序列的元素,遍历后返回开始和结束点之间的所有元素。也可以理解为默认步长是1,即没有设置步长时,步长隐式设置值为1。输入如下:

>>> number[0:10:1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

由上面的示例可以看到,分片包含另一个数字。这种方式就是步长的显式设置。看起来和隐式设置步长没什么区别,得到结果和之前也一样。但若将步长设置为比1大的数,结果会怎样呢?输入如下:

>>> number[0:10:2]
[1, 3, 5, 7, 9]

由上面的输出结果可以看到,对于number序列,设置步长为2时,得到的结果就是我们前面想要的奇数序列。

由结果可知,步长设置为大于1的数时,会得到一个跳过某些元素的序列。例如,我们上面设置的步长为2,得到的序列是从开始到结束每隔1个元素的序列。比如还可以这样使用:

>>> number[0:10:3]
[1, 4, 7, 10]
>>> number[2:6:3]
[3, 6]
>>> number[2:5:3]
[3]
>>> number[1:5:3]
[2, 5]

由以上输出可以看到,使用步长的方式还是很灵活的。

除了上面的使用方式外,设置前面两个索引为空的捷径也可以使用。操作如下:

>>> number[::3]
[1, 4, 7, 10]

上面的操作将序列中每3个元素的第一个提取出来,前面两个索引都设置为空。步长设置为0是否可行呢?输入如下:

>>> number[::0]
Traceback (most recent call last):
  File "<pyshell#73>", line 1, in <module>
    number[::0]
ValueError: slice step cannot be zero

输出结果告诉我们步长不能为0。

步长是否可以为负数呢?输入如下:

>>> number[10:0:-2]
[10, 8, 6, 4, 2]
>>> number[0:10:-2]
[]
>>> number[::-2]
[10, 8, 6, 4, 2]
>>> number[5::-2]
[6, 4, 2]
>>> number[:5:-2]
[10, 8]
>>> number[::-1]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> number[10:0:-1]       #第二个索引为0,取不到序列中的第一个元素
[10, 9, 8, 7, 6, 5, 4, 3, 2]
>>> number[10::-1]        #设置第二个索引为空,可以取到序列的一个元素
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> number[2::-1]         #设置第二个索引为空,可以取到序列的一个元素
[3, 2, 1]
>>> number[2:0:-1]         #第二个索引为0,取不到序列中的第一个元素

上面的输出结果好像不太好理解,使用负数步长时的结果怎么跟使用正数步长的结果相反呢?这就是正数步长和负数步长的不同。

对于正数步长,Python会从序列的头部开始向右提取元素,直到最后一个元素;对于负数步长,则是从序列的尾部开始向左提取元素,直到第一个元素。正数步长必须让开始点小于结束点,而负数步长必须让开始点大于结束点。

通过示例可以看到,使用负数步长时,设置第二个索引为空才能取到序列的第一个元素。

3.1.3 序列相加

使用加号可以进行序列的连接操作,输入如下:

>>> [1,2,3]+[4,5,6]
[1, 2, 3, 4, 5, 6]
>>> a=[1,2]
>>> b=[5,6]
>>> a+b
[1, 2, 5, 6]
>>> s='hello,'
>>> w='world'
>>> s+w
'hello,world'

由上面的输出结果可以看到,数字序列可以和数字序列通过加号连接,连接后的结果还是数字序列;字符串序列也可以通过加号连接,连接后的结果还是字符串序列。数字序列是否可以和字符串序列相加呢?结果是数字序列还是字符串序列呢?输入如下:

>>> [1,2]+'hello'
Traceback (most recent call last):
  File "<pyshell#103>", line 1, in <module>
    [1,2]+'hello'
TypeError: can only concatenate list (not "str") to list
>>> type([1,2])      #取得[1,2]的类型为list
<class 'list'>
>>> type('hello')    #取得hello 的类型为字符串
<class 'str'>

由上面的输出结果可以看到,数字序列和字符串序列不能通过加号连接。错误提示的信息是:只能列表和列表相连。

由试验结果可以得知:只有类型相同的序列才能通过加号进行序列连接操作,不同类型的序列不能通过加号进行序列连接操作。

3.1.4 乘法

注意此处的乘法并不是数学中定义的乘法。

用一个数字x乘以一个序列会生成新的序列。在新的序列中,原来的序列将被重复x次,这就是序列中的乘法。在交互模式下输入:

>>> 'hello'*5
'hellohellohellohellohello'
>>> [7]*10
[7, 7, 7, 7, 7, 7, 7, 7, 7, 7]

从输出结果看到,序列被重复了对应的次数,而不是做了数学中的乘法运算。

在Python中,序列的乘法有什么特殊之处呢?

如果要创建一个重复序列,就可以像上面的示例一样乘以一个想要得到的序列长度的数字,这样可以快速得到需要的列表,非常方便。

空列表可以简单通过两个中括号([])表示,表示里面什么东西都没有。如果想创建一个占用10个或更多元素的空间,却不包括任何有用内容的列表,该怎么办呢?我们可以像上面的示例一样乘以10或对应的数字,得到需要的空列表,也很方便。

如果要初始化一个长度为x的序列,就需要让每个编码位置上都是空值,此时需要一个值代表空值,即里面没有任何元素,可以使用None。None是Python的内建值,确切含义是“这里什么也没有”。例如,输入如下:

>>> sq=[None]*5 #初始化sq 为含有5 个None 的序列
>>> sq
[None, None, None, None, None]

从示例我们可以看到,Python中的序列乘法可以帮助我们快速做一些初始化操作。序列乘法做一些重复操作、空列表和None初始化操作还是挺方便的。

3.1.5 成员资格

为了检查一个值是否在序列中,Python为我们提供了in运算符。in运算符和前面讨论过的运算符有些不同。in运算符用于检验某个条件是否为真,并返回检验结果,检验结果为真返回True,结果为假返回False。这种运算符称作布尔运算符,返回的真值叫作布尔值。关于布尔运算符的更多内容会在后续章节中进行介绍。

下面我们尝试使用in在交互模式输入:

>>> greeting='hello,world'
>>> 'w' in greeting #检测w 是否在字符串中
True
>>> 'a' in greeting
False
>>> users=['xiaomeng','xiaozhi','xiaoxiao']
>>> 'xiaomeng' in users #检测字符串是否在字符串列表中
True
>>> 'xiaohuai' in users
False
>>> numbers=[1,2,3,4,5]
>>> 1 in numbers  #检测数字是否在数字列表中
True
>>> 6 in numbers
False
>>> eng='** Study python is so happy!**'
>>> '**' in eng #检测一些特殊字符是否在字符串中
True
>>> '$' in eng
False
>>> 'a' in numbers
False
>>> 3 in greeting
Traceback (most recent call last):
  File "<pyshell#123>", line 1, in <module>
    3 in greeting
TypeError: 'in <string>' requires string as left operand, not int

由上面的输出结果可以看到,使用in可以很好地检测字符或数字是否在对应的列表中。并且可以看出,数字类型不能在字符串类型中通过in进行成员资格检测,而字符串类型可以在数字列表中通过in进行成员资格检测。

3.1.6 长度、最小值和最大值

Python为我们提供了长度、最大值和最小值的内建函数,对应的内建函数分别为len、max和min。

这3个函数该怎么使用呢?在交互模式输入:

>>> numbers=[300,200,100,800,500]
>>> len(numbers)
5
>>> max(numbers)
800
>>> min(numbers)
100
>>> max(5,3,10,7)
10
>>> min(7,0,3,-1)
-1

由上面的结果可以看到,len函数返回序列中所包含元素的数量,max函数和min函数分别返回序列中最大和最小的元素。在该示例中,前面几个函数的输入参数都是序列,可以使用前面的解释理解。max和min函数的参数不是一个序列,而是以多个数字直接作为参数,此处直接求取多个数字的最大值和最小值。 FLjN8EUp4nRD0fyxCKi4A0lB0WpdBTHuL5S+Bltb0clN1JJqE2wdi81a9LXiVu36

点击中间区域
呼出菜单
上一章
目录
下一章
×