第2章:列表和元组 (原书抄写)

本文深入介绍了Python中的序列概念,包括列表、元组等基本数据结构的使用方法,并详细讲解了索引、分片、序列相加及乘法等常用操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

     在Python中,最基本的数据结构式序列。序列中的每个元素被分配一个序号--即元素的位置,也称为索引。

 

  2.1 序列概览

   Python包含6种内建的序列,本章重点讨论最常见的两种类型:列表和元组。其他的内建序列类型有字符串、Unicode字符串、bugger对象和xrange对象。

 

   列表和元组的主要区别在于,列表可以修改,元组则不能。

也就是说如果要根据要求来添加元素,那么列表可能会更好用;

而出于某些原因,序列不能修改的时候,使用元组则更为合适。

使用后者的理由通常是技术性的,它与Python内部的运作方式有关。这也是内建函数可能返回元组的原因。这句没看懂)

一般来说,在几乎所有情况下列表都可以替代元组(第4章将会介绍一个需要注意的例外情况:使用元组作为字典的键。在这种情况下,因为键不可修改,所以就不能使用列表)。

   

    在需要操作一列数值的时候,序列很好用。可以用序列表示数据库中一个人的信息----第1个元素是姓名,第2个元素是年龄。根据上述内容编写一个列表(列表的各个元素通过逗号分隔,写在方括号中),如下例所示:

>>> edward =['Edward Gumby',42]

 

   同时,序列也可以包含其他的序列,因此,构建如下一个人员信息的列表也是可以的,这个列表就是你的数据库:

 

>>> edward = ['Edward Gumby',42]

>>> john = ['John Smith',50]

>>>database = [edward,john]

>>>database

[['Edward Gumby',42].['John.Sminth',50]]

 

注意:Python之中还有一种名为容器的数据结构。容器基本上是包含其他对象的任意对象。

序列(例如列表和元组)和映射(例如字典)是两类主要的容器。序列中的每个元素都有自己的编号,而映射中的每个元素则有一个名字(也称为键)。在第4章会介绍更多有关映射的知识。至于既不是序列也不是映射的容器类型,集合(set)就是一个例子,请参见第10章的相关内容。

 

2.2 通用序列操作

  所有序列类型都可以进行某些特定的操作。这些操作包括:索引、分片、加、乘以及检查某个元素是否属于序列的成员(成员资格)。

除此之外,Python还有计算序列长度、找出最大元素和最小元素的内建函数。

 

  注意:本节有一个重要的操作没有提到----迭代。对序列进行迭代的意思是:依次对序列中的每个元素重复执行某些操作。

 

2.2.1  索引

    序列中的所有元素都是有编号的----从0开始递增。这些元素可以通过编号分别访问,如下例所示:

>>> greeting = 'Hello'

>>> greeting[0]

'H'

 注意: 字符串就是一个由字符组成的序列。索引0指向第1个元素,在这个例子中就是字母H。

     这就是索引。可以通过索引获取元素。所有序列都可以通过这种方式进行索引。使用负数索引时,Python会从右边,也就是从最后1个元素开始计数。最后1个元素的位置编号是-1(不是-0,因为那会和第1个元素重合);

  >>> greeting[-1]

  '0'

字符串字面值(就此而言,其他序列字面量亦可)能够直接使用索引,而不需要一个变量引用它们。两种做法的效果是一样的:

>>>'Hello'[1]

'e'

如果一个函数调用返回一个序列,那么可以直接对返回结果进行索引操作。例如,假设你只对用户输入年份的第4个数字感兴趣,那么,可以进行如下操作:

>>> fourth = raw_input('Year: ')[3]

Year:2005

>>>fourth

'5'


以下代码清单是一个示例程序,它要求输入年、月(1~12的数字)、日(1~31),然后打印出相应日期的月份名称,等等。

代码清单 2-1 索引示例

#根据给定的年月日以数字形式打印出日期

months = [

  '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']

 

---------网上搜到的endings这段的注解:一个月最多有31天,如果按英文表示的话,对应的日期就是
1st, 2nd, 3rd,
4th, ... , 20th,   #共有17个,所以是17*['th']
21st, 22nd, 23rd,
24th, ... , 30th,   #共有7个,所以是7*['th']
30st

 

    year =raw_input('Year: ')

    month= raw_input('Month(1-12): ')

    day   = raw_input('Day(1-31): ')

 

    month_number =int(month)

    day_number = int(day)

#记得要将月份和天数减1,以获得正确的索引

   month_name =months[month_number-1]

   ordinal =day+endings[day_number-1]

 

   print  month_name+'  '+ ordinal+'. '+year

 

   以下是程序执行的一部分结果:

   Year:2014

   Month(1-12):2

   Day (1-31):17

   February 17th , 2014

 

 

2.2.2 分片

    与使用索引来访问单个元素类似,可以使用分片操作来访问一定范围内的元素。分片通过冒号相隔的两个索引来实现:

>>> tag ='<a href="http://www.python.org">Python web site</a>'

>>>tag[9:30]

'http://www.python.org'

>>>tag[332:-4]

'Python web site'

分片操作对于提取序列的一部分是很有用的。而编号在这里显得尤为重要。第1个索引是需要提取部分的第1个元素的编号,而最后的索引则是分片之后剩下部分的第1个元素的编号。

请参见如下代码:

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

>>> numbers[3:6]

[4,5,6]

>>> numbers[0:1]

[1]

简而言之,分片操作的实现需要提供两个索引作为边界,第1个索引的元素是包含在分片内的,而第2个则不包含在分片内。

1、优雅的捷径
假设需要访问最后3个元素(根据先前的例子),那么当然可以进行显示的操作:

>>>numbers[7:10]

[8,9,10]

现在,索引10指向的是第11个元素-----这个元素并不存在,却是在最后一个元素之后。明白了吗?

现在,这样的做法是可行的。但是,若需要从列表的结尾开始计数呢?

>>>numbers[-3:-1]

[8,9]

看来并不能以这种方式访问最后的元素。那么使用索引0作为最后一部的下一步操作所使用的元素,结果又会怎样呢?

>>> numbers[-3:0]

[]

这并不是我们所要的结果。实际上,只要分片中最左边的索引比它右边的晚出现在序列中(在这个例子中是倒数第3个比第2个晚出现),结果就是一个空的序列。幸好,可以使用一个捷径:

如果分片所得部分包括序列结尾的元素,那么,只需置空最后一个索引即可:

>>> numbers[-3: ]

[8,9,10]

 

这种方法同样适用于序列开始的元素:

>>> numbers[ :3]

[1,2,3]

实际上,如果需要复制整个序列,可以将两个索引都置空:

>>> number[ : ]

[1,2,3,4,5,6,7,8,9,10]

代码清单2-2是一个小程序,它会提示输入URL,然后提取域名。

------------chouningning注解:当你读不懂的时候,继续往后读,也许你会找到答案,不要在一个点上纠结。

代码清单2-2  分片示例

  # 对http://www.something.com形式的URL进行分割

 

url = raw_input('Please enter the URL: ')

domain =url[11:-4]

 

print "Domain name: " +domain

以下是程序运行的实例:

 

Please enter the URL: http://www.Python.org

Domain name:python

 

2、更大的步长

    进行分片的时候,分片的开始和结束点需要进行指定(不管是直接还是间接)。而另外一个参数(在Python 2.3加入到内建类型)----步长(step length)----通常都是隐式设置的。在普通的分片中,步长是1----分片操作就是按照这个步长逐个遍历序列的元素,然后返回开始和结束点之间的所有元素。

   >>> numbers[0:10:1]

[1,2,3,4,5.6,7,8,9,10]

    在这个例子中,分片包含了另外一个数字。没错,这就是步长的显式设置。如果步长被设置为比1大的数,那么就会跳过某些元素。例如,步长为2的分片包括的是从开始到结束每隔1个的元素。

>>>numbers[0:10:2]

[1,3,5,7,9]

>>>numbers[3:6:3]

[4]

之前提及的捷径也可以使用。如果需要将每4个元素中的第1个提取出来,那么只要将步长设置为4即可:

>>>numbers[::4]

[1,5,9]

当然,步长不能为0--那不会向下执行--但步长可以是负数,即从右到左提取元素:

>>> numbers[8:3:-1]

[9,8,7,6,5]

>>> numbers[10,0:-2]

[10,8,6,4,2]

>>>numbers[0:10:-2]

[]

>>>numbers[::-2]

[10,8,6,4,2]

>>> numbers[5::-2]

[6,4,2]

>>> numbers[:5:-2]

[10,8]

chouningning注解:这里的5代表序列里的6,所以6不在分片内。从数字10,9,8,7 四个数字中从右到左步长为2提取元素。所以是10,8。

 

 

 

在这里要得到正确的分片结果需要动些脑筋。开始点的元素(最左边元素)包括在结果之中,而结束点的元素(最右边的元素)则不在分片之内。当使用一个负数作为步长时,必须让开始点(开始索引)大于结束点。在没有明确指定开始点和结束点的时候,正负数的使用可能会带来一些混淆。不过再这种情况下Python会进行正确的操作:对于一个正数步长,Python会从序列的头部开始向右提取元素,直到最后一个元素;而对于负数步长,则是从序列的尾部开始向左提取元素,直到第一个元素。

 

2.2.3  序列相加

     通过使用加号可以进行序列的连接操作:

 >>> [1,2,3]+[4,5,6]

[1,2,3,4,5,6]

>>>'Hello, '+ 'world!'

'Hello, world!'

>>> [1,2,3]+'world!'

Traceback (innermost last):

 

TypeError: can  only concatenate list (not "string") to list

正如错误信息所提示的,列表和字符串时无法连接在一起的,尽管它们都是序列。简单来说,两种相同类型的序列才能进行连接操作。

 

2.2.4 乘法

  用数字x乘以一个序列会生成新的序列,而在新的序列中,原来的序列将被重复x次。

>>> 'python' * 5

'pythonpythonpythonpythonpython'

>>>[42]*10

[42,42,42,42,42,42,42,42,42,42]

None、空列表和初始化

空列表可以简单地通过两个中括号进行标示([]) ------里面什么东西都没有。但是,如果想创建一个占用十个元素的空间,却不包括任何有用内容的列表,又该怎么办呢?可以像前面那样使用[42]*10,或者使用[0]*10,这会更加实际一些。这样就生成了一个包括10个0的列表。然而,有时候可能会需要一个值来代表空值----意味着没有在里面放置任何元素。这个时候就需要使用None。None是一个Python的内建值,它的确切含义是“这里什么也没有”。因此,如果想初始化一个长度为10的列表,可以按照下面的例子来实现:

>>>sequence = [None]*10

>>>sequence

[None,None,None,None,None,None,None,None,None,None]

 

 

代码清单2-3的程序会在屏幕上打印一个由字符组成的“盒子”,而这个“盒子”在屏幕上居中而且能根据用户输入的句子自动调整大小。

  代码可能看起来很复杂,但只使用基本的算法----计算出有多少空格、破折号等字符,然后将它们放置到合适的位置即可。

 

代码清单2-3  序列(字符串)乘法示例

 # 以正确的宽度在居中的盒子”内打印一个句子

 

# 注意,整数除法运算符(//)只能用在Python 2.2以及后续版本,在之前的版本中,只使用普通除法(/)

 

sentence =raw_input("Sentence: ")

 

screen_width =80

text_width =len (Sentence)

box_width =text_width + 6

left_margin = (screen_width -box_width) //2

 

print

print ' '* left_margin +'+' +'-'*(box_width-2) + '+'

print ' '* left_margin +'|+''*text_width           + '|'

 

------------Page 50

 

 

chouningning注解:按作者的代码,上下的两条线要长于中间部分。总觉得第3和倒数第3行应该是' '*box_width

试了下作者的,得不到书中附图的效果。

但是,用以下自己修改过的代码可以达到图中效果:

print
print' '*left_margin+'+'+'-'*(box_width-2)+'+'
print' '*left_margin+'|'+' '*(box_width-2)+ '|'
print' '*left_margin+'|'+' '*((box_width-text_width-2)//2)+sentence+' '*((box_width-text_width-2)//2)+'|'
print' '*left_margin+'|'+' '*(box_width-2)+ '|'
print' '*left_margin+'+'+'-'*(box_width-2)+'+'
print

附图:

 

 

 

 

 

 

 

 

 

 移步网易博客:优快云的文本编辑器真的很渣。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值