Python入门(2):列表和元组

本文深入介绍了Python中的数据结构,包括序列、容器、列表、元组等基本概念及其操作方法,如索引、分片、加法、乘法、成员资格判断等。此外,还详细解释了列表和元组的特点及应用场景。

首先引入数据结构。数据结构是通过某种方式(例如对元素进行编号)组织在一起的数据元素的集合。数据元素可以是数字或者字符,甚至可以是其他数据结构。

Python中,最基本的数据结构是序列(sequence)。序列中的每个元素被分配一个序号——即元素的位置,也称为索引。序列可以包含其他的序列。

edward=['Edward Gumby',42]
john=['John Smith',50]
database=[edward,john]
print(database)             #[['Edward Gumby', 42], ['John Smith', 50]]

1、容器

Python中有一种名为容器的数据结构。容器基本上是包含其他对象的任意对象。序列(例如列表和元组)和映射(例如字典)是两类主要的容器。序列中的每个元素都有自己的编号,映射中的每个元素有一个名字(也称为键)。至于既不是序列也不是映射的容器类型,集合(set)是一个例子。

2、序列

Python包含6种内建的序列:列表、元组、字符串、Unicode字符串、buffer对象和xrange对象。

列表和元组是最常用的两种类型,它们最大的区别是,列表可修改,元组不能。通常,内建函数会返回元组,自己编写程序时几乎所有情况都可用列表代替元组(例外:使用元组作为字典的键)。

所有序列类型都可以进行某些特定的操作,包括:索引(indexing)、分片(slicing)、加(adding)、乘(multiplying)、检查某个元素是否属于序列的成员(成员资格),以及计算序列长度、找出最大元和最小元的内建函数。

(1)索引

通过索引获取元素。序列中的所有元素都是有编号的,从左往右是从0开始递增,从右往左是从-1开始递减。

字符串是一个由字符组成的序列。字符串字面值(其他序列字面量亦可)可直接使用索引,而不需要用一个变量来引用它们。

如果一个函数调用返回一个序列,则可直接对返回结果进行索引操作。

greeting='hello'
print(greeting[0])          #h
print(greeting[-1])         #o
print('hello'[1])           #e
fourth=input('Year: ')[3]   #Year: 2018
print(fourth)               #8

索引示例:输入年月日,输出日期

months=['January','February','March','April','May','June','July','August',\
'September','October','November','December']
endings=['st','nd','rd']+17*['th']\
+['st','nd','rd']+7*['th']+['st']
year=input('Year: ')                            #Year: 2018
month=months[int(input('Month(1-12): '))-1]     #Month(1-12): 2
day=input('Day(1-31): ')                        #Day(1-31): 23
dayth=day+endings[int(day)-1]
print(month+' '+dayth+', '+year)                #February 23rd, 2018

(2)分片

与使用索引访问单个元素类似,可使用分片访问一定范围的元素。分片通过冒号隔开的两个索引来实现。第1个索引是要提取的第1个元素的编号,第2个索引则是分片之后剩余部分的第1个元素的编号,即:第1个索引的元素包含在分片内,而第2个不包含在分片内。

若分片中第1个索引比第2个索引晚出现在序列中,则结果是一个空序列。

如果分片要包括序列结尾元素,则只需置空第2个索引即可。若置空第1个索引,则包括序列开头。若要复制整个序列,可将两个索引都置空。

分片还有一个参数——步长。步长通常都是隐式设置的。步长不能为0(那不会执行),但可正可负。若步长为负,则分片从右到左提取元素,必须让开始点(开始索引)大于结束点。

在没有明确指定开始的和结束点时,对正步长,Python会从序列的头部开始向右提取元素,直到最后一个元素;对负步长,则是从序列的尾部开始向左提取元素,直到第一个元素。

numbers=[1,2,3,4,5,6,7,8,9,10]
print(numbers[3:6])             #[4, 5, 6]
print(numbers[0:1])             #[1]
print(numbers[7:10])            #[8, 9, 10]
print(numbers[-3:-1])           #[8, 9]
print(numbers[-3:0])            #[]
print(numbers[-3:])             #[8, 9, 10]
print(numbers[:3])              #[1, 2, 3]
print(numbers[:])               #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(numbers[0:10:1])          #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(numbers[::2])             #[1, 3, 5, 7, 9]
print(numbers[::4])             #[1, 5, 9]
print(numbers[3:6:3])           #[4]
print(numbers[1::2])            #[2, 4, 6, 8, 10]
print(numbers[::-2])            #[10, 8, 6, 4, 2]
print(numbers[8::-2])           #[9, 7, 5, 3 ,1]
print(numbers[5::-2])           #[6, 4, 2]
print(numbers[:5:-2])           #[10, 8]

分片示例:输入URL,提取域名

#对http://www.something.com形式的URL进行分割
url=input('Please enter the URL: ') #Please enter the URL: http://www.python.org
domain=url[11:-4]
print('Domain name: '+domain)       #Domain name: python

(3)加

通过加运算符可进行序列的连接操作。但是列表和字符串是无法连接在一起的。只有两种相同类型的序列才能相加连接。

print([1, 2, 3]+[4, 5, 6])  #[1, 2, 3, 4, 5, 6]
print('Hello, '+'world!')   #Hello, world!

(4)乘

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

空列表可以简单地通过两个中括号进行表示([])。

None是Python的内建值。可以用None来初始化一个一定长度的列表。

print('python'*5)   #pythonpythonpythonpythonpython
print([42]*10)      #[42, 42, 42, 42, 42, 42, 42, 42, 42, 42]
sequence=[None]*10
print(sequence)     #[None, None, None, None, None, None, None, None, None, None]

(5)成员资格

为了检查一个值是否在序列中,使用in运算符。in运算符检查某个条件是否为真,若条件为真则返回True,若条件为假则返回False。这样的运算符叫做布尔运算符,返回的值叫做布尔值。

permissions='rw'
print('w' in permissions)                       #True
print('x' in permissions)                       #False
users=['lyw','xzq','tea']
print(input('Enter your user name: ') in users) #Enter your user name: lyw
                                                #True
subject='$$$ Get rich now!!! $$$'
print('$$$' in subject)                         #True

成员资格示例:检查用户名和PIN码是否存在于数据库

database=[['albert','1234'],['dilbert','4242'],
['smith','7524'],['jones','9843']]
username=input('User name: ')                           #User name: smith
pin=input('PIN code: ')                                 #PIN code: 7524
if [username,pin] in database: print('Access granted')  #Access granted

(6)序列长度、最大元、最小元

len(),max(),min()都是内建函数。len()返回序列中所包含元素的数量,max()和min()分别返回序列中的最大元和最小元。这里,max()和min()可以多个数字直接作为参数。

numbers=[100, 34, 678]
print(len(numbers), max(numbers), min(numbers)) #3 678 34
print(max(2,3))                                 #3
print(min(9,3,2,5))                             #2

3、列表

列表不同于元组和字符串的地方是:列表可以改变,并且列表有很多有用的、专门的方法。

因为字符串不能像列表一样被修改,所以有时需要根据字符串创建列表。list()可以实现这个操作。反过来,''.join()可以把一个由字符组成的列表转换为字符串。

Remark:list()适用于所有类型的序列,而不只是字符串。

somelist=list('Hello')
print(somelist)             #['H', 'e', 'l', 'l', 'o']
print(''.join(somelist))    #Hello

列表除了可以使用所有适用于序列的标准操作(如索引、分片、加、乘)外,还有如下改变列表的方法:

(1) 元素赋值

使用索引标记来为某个位置明确的元素赋值。不能为一个位置不存在的元素进行赋值。如果要那样做,必须先用None初始化一个足够长度的列表。

x=[1, 1, 1]
x[1]=2
print(x)        #[1, 2, 1]

(2) 删除元素

使用del()语句实现。del()除了删除列表中的元素,还能用于删除其他元素,比如字典元素甚至是其他变量的删除。

names=['Alice','Beth','Cecil','Dee-Dee','Earl']
del(names[2])
print(names)            #['Alice', 'Beth', 'Dee-Dee', 'Earl']
numbers=[1, 2, 3, 4, 5]
del(numbers[1:4])
print(numbers)          #[1, 5]

(3) 分片赋值

分片是一个非常强大的特性。使用分片赋值时,可以使用与原序列不等长的序列将分片替换。

分片赋值语句可以在不需要替换任何原有元素的情况下插入新的元素,也可通过分片赋值来删除元素。

name=list('Perl')
name[2:]=list('ar')
print(name)             #['P', 'e', 'a', 'r']

name=list('Perl')
name[1:]=list('ython')
print(name)             #['P', 'y', 't', 'h', 'o', 'n']

numbers=[1, 5]
numbers[1:1]=[2, 3, 4]
print(numbers)          #[1, 2, 3, 4, 5]

numbers[1:4]=[]
print(numbers)          #[1, 5]

(4) 列表方法

方法是一个与某些对象有紧密联系的函数,对象可能是列表、数字,也可能是字符串或者其他类型的对象。调用方法的一般格式为:对象.方法(参数)。列表提供了很多方法,用于检查或者修改其中的内容:

① append:在列表末尾追加新的对象

lst=[1,2,3]
lst.append(4)
print(lst)                  #[1, 2, 3, 4]

② count:统计某个元素在列表中出现的次数

print(['to','be','or','not','to','be'].count('to')) #2
x=[[1,2],1,1,[2,1,[1,2]]]
print(x.count(1))                                   #2
print(x.count([1,2]))                               #1

③ extend:在列表末尾一次性追加另一个序列中的多个值,即用新列表扩展原有的列表

(注意,与连接(加)操作的区别在于:extend方法修改了被扩展的序列,而原始的连接操作会返回一个全新的列表,不改变原始序列。也可用分片赋值来实现相同的结果,但是分片赋值代码的可读性不如extend方法好。)

a=[1,2,3]
b=[4,5,6]
a.extend(b)
print(a)                    #[1, 2, 3, 4, 5, 6]
a=[1,2,3]
b=[4,5,6]
a[len(a):]=b
print(a)                    #[1, 2, 3, 4, 5, 6]

④ index:从列表中找出某个值第一个匹配项的索引位置

knights=['We','are','the','knights','who','say','ni']
position=knights.index('who')
print(position)                                     #4
print(knights[position])                            #who

⑤ insert:将对象插入到列表中

(注意,与extend方法一样,insert方法也可用分片赋值来实现,但可读性不如insert方法好。)

numbers=[1,2,3,5,6,7]
numbers.insert(3,'four')
print(numbers)              #[1, 2, 3, 'four', 5, 6, 7]
numbers=[1,2,3,5,6,7]
numbers[3:3]=['four']
print(numbers)              #[1, 2, 3, 'four', 5, 6, 7]

⑥ pop:移除列表中的一个元素(默认是最后一个),并且返回该元素的值

(注意,pop方法是唯一一个既能修改列表又返回元素值(除了None)的列表方法。使用pop方法可以实现一种常见的数据结构——栈,因为遵循后进先出(LIFO)原则。入栈可用append方法来代替。若要实现一个先进先出(FIFO)的队列,可使用insert(0,...)来代替append方法,或者继续使用append方法,但用pop(0)来代替pop()。更好的解决方案是使用collection模块中的deque对象。)

x=[1,2,3]
print(x.pop())              #3
print(x)                    #[1, 2]
print(x.pop(0))             #1
print(x)                    #[2]
x=[1,2,3]
x.append(x.pop())
print(x)                    #[1, 2, 3]

⑦ remove:移除列表中某个值的第一个匹配项

x=['to','be','or','not','to','be']
x.remove('be')
print(x)                    #['to', 'or', 'not', 'to', 'be']

⑧ reverse:将列表中的元素反向存放

(注意:若要对一个序列进行反向迭代,可使用reversed函数。这个函数不返回一个列表,而是返回一个迭代器对象,这时可使用list函数把返回的对象转换成列表。)

x=[1,2,3]
x.reverse()
print(x)                    #[3, 2, 1]
x=[1,2,3]
print(list(reversed(x)))    #[3, 2, 1]

⑨ sort:在原位置对列表进行排序。

(注意,当用户需要一个排好序的的列表副本,同时又保留原有列表不变时,要先把x的副本赋值给y,然后对y进行排序。注意,只简单地把x赋值给y(y=x)是没用的,因为这样做就让x和y都指向同一个列表了。

另一种获取已排序的列表副本的方法是使用sorted函数,这个函数实际上可以用于任何序列,但总是返回一个列表。

若想把一些元素按相反的顺序排列,可以先用sort(或者sorted)然后用reverse方法,或者也可用reverse参数,见下。)

x=[4,6,2,1,7,9]
x.sort()
print(x)                    #[1, 2, 4, 6, 7, 9]
x=[4,6,2,1,7,9]
y=x[:]
y.sort()
print(x)                    #[4, 6, 2, 1, 7, 9]
print(y)                    #[1, 2, 4, 6, 7, 9]
x=[4,6,2,1,7,9]
y=sorted(x)
print(x)                    #[4, 6, 2, 1, 7, 9]
print(y)                    #[1, 2, 4, 6, 7, 9]
print(sorted('Python'))     #['P', 'h', 'n', 'o', 't', 'y']

⑩ 高级排序:key, reverse

关键字参数key:必须提供一个在排序过程中使用的函数。然而,该函数并不是直接用来确定对象的大小,而是为每个元素创建一个键,然后所有元素根据键来排序。若要根据元素的长度进行排序,那么可使用len作为键函数。

关键字参数reverse:是简单的布尔值(True或False),用来指明列表是否要进行反向排序。

key、reverse参数都可用于sorted函数。多数情况下,为key提供自定义函数是非常有用的。

x=['aardvark','abalone','acme','add','aerate']
x.sort(key=len)
print(x)                    #['add', 'acme', 'aerate', 'abalone', 'aardvark']

x=[4,6,2,1,7,9]
x.sort(reverse=True)
print(x)                    #[9, 7, 6, 4, 2, 1]
x=['aardvark','abalone','acme','add','aerate']
y=sorted(x,key=len)
print(x)                    #['aardvark', 'abalone', 'acme', 'add', 'aerate']
print(y)                    #['add', 'acme', 'aerate', 'abalone', 'aardvark']

x=[4,6,2,1,7,9]
y=sorted(x,reverse=True)
print(x)                    #[4, 6, 2, 1, 7, 9]
print(y)                    #[9, 7, 6, 4, 2, 1]

小结:

修改原来的列表、没有返回值的列表方法:append,extend,insert,remove,reverse,sort;

有返回值的列表方法:count,index,pop。

4、元组

元组是不可变的序列(一旦创建就是固定的,不能修改)。创建元组的语法很简单:若用逗号分隔了一些值,就自动创建了元组。元组大部分时候是通过圆括号括起来的。空元组可以用不包含任何内容的两个圆括号来表示。若要实现只包括一个值的元组,必须加个逗号。

x=1,2,3
y=(1,2,3)
z=()
print(x,y,z)    #(1, 2, 3) (1, 2, 3) ()
a=42
b=42,
c=(42,)
print(a,b,c)    #42 (42,) (42,)
r=3*(40+2)
s=3*(40+2,)
print(r,s)      #126 (42, 42, 42)

tuple函数的功能与list函数基本上是一样的:以一个序列作为参数并把它转换为元组。【即:list(seq)是把序列转换为列表,tuple(seq)是把序列转换为元组。】若参数就是元组,则该参数被原样返回。

除了创建元组和访问元组元素之外,元组没有太多其他操作。元组的分片还是元组,就像列表的分片还是列表一样。

print(tuple([1,2,3]))   #(1, 2, 3)
print(tuple('abc'))     #('a', 'b', 'c')
print(tuple((1,2,3)))   #(1, 2, 3)
x=1,2,3
print(x[1])             #2
print(x[0:2])           #(1, 2)

元组的存在有以下两个重要原因:

1)元组可以在映射(和集合的成员)中当作键使用——而列表则不行;

2)元组作为很多内建函数和方法的返回值存在。

 

以上。参考书是Magnus Lie Hetland著的《Python基础教程(第2版·修订版)》Chapter 2.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值