第二章:列表和元组
前言
关于本章,我将会将两个新的数据结构(数据结构的定义请参见数据结构),在Python中,最基础的数据结构是序列,序列就是对每个元素进行编号(就是其位置或者索引,注意,其中第一个元素的索引为0,以此类推)。当然,书中也提到了负索引,后面会跟大家逐步介绍。
本章的前部分是对索引进行概述,然后介绍一些适用于所有序列(包括列表和元组)的操作。这些操作也适用于本章一些示例中将使用的字符串,下一章将全面介绍字符串操作。讨论这些基本知识后,将着手介绍列表,看看它们有什么特别之处,然后讨论元组。元组是一种特殊的序列,类似与列表,只是不能修改。
2.1 序列概述
Python内置了多种的序列,本章重点讨论其中用的最常见的两种:列表和元组。另外一种重要的序列是字符串,将在下一章更详细的讨论。
列表和元组主要的不同在于:列表是可以修改的,而元组不可以(注意:这意味着列表适用于需要中途添加元素的情况,而元组适用于处于某种情况需禁止修改的情况)。在自己编写的程序中,几乎在所有的情况下都可以使用列表来代替元组。一种例外的情况就是将元组作为字典键,这在后面的第四章进行讨论。在这种情况下,不能使用列表来代替元组,因为字典键是不允许修改的。
举例:
在需要处理一系列的值时,序列很有用。在数据库中,你可能使用序列来表示人,其中第一个元素为姓名,第二个元素为年龄。如果使用列表来表示(所有元素都放入方括号内,并用逗号隔开),将类似下面这样:
>>>edward=[ ' Edward Gumby ‘,42]
当然,序列中还可以包含其他序列,因此可以创建一个由数据库中所有人员组成的列表:
>>>edward=[ ' Edward Gumby ',42 ]
>>>john=[' John Smith ',50]
>>>database=[edward,john]
>>>database
[ [ ' Edward Gumby ',42] ,[ 'John Smith ' ,50] ]
注意:Python 支持一种数据结构的基本概念,名为容器。容器基本上就是可包括其他对象的对象(这个对象是生活中的对象还是当时将的C++中的这种对象???)。两种主要的容器是序列(如列表和元组)和映射(如字典)。在序列中,每个元素都有自己的编号,而在映射中,每个元素都有自己的名称(也叫键)。映射将在第四章详细的讨论。有一种既不是序列也不是映射的容器,就是集合(set),将在第十章讨论。
2.2 通用的序列操作
有几种操作适用于所有的序列,包括索引,切片,相加,相乘和成员资格检查。另外,Python还提供一些内置函数,可用于确定序列的长度以及找到序列中最大和最小的元素。
注意:有一些重要的操作这里不会介绍,它就是迭代,对序列进行迭代意味着对其每个元素都要执行特定的操作。有关迭代的具体信息,请参见5.5节
2.2.1 索引
序列中每个元素都要进行编号-----------从0开始递增。你可像下面这样使用编号来访问各个元素:
>>>greeting = 'Hello'
>>>greeting[0]
'H'
注意:字符串就是由字符组成的序列。索引0指向第一个元素,这里为字符H。不同于其他一些语言,Python没有专门用于表示字符串的类型,因此一个字符就是只包含一个元素的字符串
这称为索引。你可使用索引来获取元素。这种索引方式适用于所有索引。当你使用负数索引时,Python将从右(即最后一个元素)开始往左数,因此-1是最后一个元素的位置。
>>>greeting[-1]
'o'
对于字符串字面量(以及其他序列字面量),可直接对其执行索引操作,无需先将其赋给变量。这与先赋给变量在对变量执行索引操作的效果一样的。
>>> 'Hello' [1]
'e'
如果函数调用返回一个序列,可直接对其执行索引操作。例如,如果你只想获取用户输入的年份的第4位,可像下面这样做:
>>>fourth=input('Year: ‘)[3]
Year=2005
>>>fourth
'5'
代码清单2-1所示程序:要求你输入年、月(数1~12)、日(数1~31),再使用相应的月份名等将日期打印出来。
代码2-1:
moths=[
'January',
'February',
'March’,
‘April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
]
#一个列表,其中包含数1~31对应的结尾
endings=['st','nd','rd']+17*['th']+['st','nd','rd']+7*['th']+['st']
year =input('Year: ')
month =input('Month(1-12): ')
day =input('Day(1-31): ')
month_number= int(month)
day_number= int(day)
#别忘了将代表年、月、日的数减1,这样才能得到正确的索引
month_name=month[month_number-1]
ordinal=day+endings[day_number-1]
print(month_name+' '+ordinal+’,‘+year)
程序运行结果类似这样:
Year: 1974
Month(1-12): 8
Day(1-31): 16
输出结果:
August 16th,1974
2.2.2 切片
除了使用索引来访问单个元素外,还可使用切片来访问特定范围内的元素。为此,可使用两个索引,并用冒号分割:
>>>tag='<a href="http://www.python.org">Python web site<\a>'
>>>tag[9:30]
'http://www.python.org'
>>>tag[32:-4]
'Python web site'
切片适用于提取序列的一部分,其中的编号非常重要:第一个索引是包含的第一个元素的编号,第二个索引是切片后余下的第一个元素的编号。请看下面的示例:
>>>numbers=[1,2,3,4,5,6,7,8,9,10]
>>>numbers[3:6]
[4,5,6]
>>>numbers[0:1]
[1]
简而言之,你提供两个索引来指定切片的边界,其中一个索引是包含第一个元素的编号,但第二个索引是切片后余下的第一个元素的编号。
1.绝妙的简写
假设你要访问前述数字列表中的最后三个元素,显然可以明确地指定这一点。
>>>number[7:10]
[8,9,10]
在这里,索引10指的是第11个元素:它并不存在,但确定是到达最后一个元素后再前进一步所在的位置。明白了吗?如果要从从列表尾部开始数,可以使用负数索引。
>>>numbers[-3:-1]
[8,9]
然而,这样好像无法包含最后一个元素。如果使用索引0,即到达列表末尾再前进一步所处的位置,结果将如何呢?
>>>numbers[-3,0]
[]
结果并不是你想要的,实际上,执行切片操作时,如果第一个索引指定的元素位于第二个索引指定的元素后面(在这里,倒数第三个元素位于第一个元素的后面),结果就为空序列。好在你能使用一种简写:如果切片结束位于序列的尾部,可省略第二个索引。
>>>numbers[-3:]
[8,9,10]
同样,如果切片始于序列头部,可省略第一个索引:
>>>numbers[:3]
[1,2,3]
实际上,要复制整个序列,可将两个索引都省略:
numbers[:]
[1,2,3,4,5,6,7,8,9,10]
代码清单2-2是一个小程序,它提示用户输入一个URL,并从中提取域名。(这里假定输入的URL类似于http://www.somedomainname.com。)