去了趟厦门,刚回来就开始学习了,真是佩服自己呢。厦门这地儿,去一次就够了,装13圣地,跟我的风格不是很搭,我主要是去吃的,各种海鲜都炒鸡便宜,冲着这个,大概还会再去一趟吧,每家都有团购,真是大众点评的根据地。好了,言归正传,开始学习吧。
第二章 列表和元组
本章开始讲数据结构。数据结构是通过某种方式(如编号)组织在一起的数据元素的集合。可以是数字或者字符,也可能是其它数据结构。
Python中最基本的数据结构是序列(sequence)。序列中每个元素都被分配一个序号(即元素的位置,也称为索引),第一个是0,第二个是1,依此类推。
2.1 序列概览
Python有6种内建的序列,本章重点讨论最常用的两种类型:列表和元组。其它序列类型有:字符串,Unicode字符串,buffer对象和xrange对象。
列表跟元组的区别:列表可以修改,元组不能。大多数情况下,列表可以替代元组(也有例外,当元组作为字典的键,因为键不可修改,所以不能用列表)
需要操作一组数据时,序列很好用。可以用序列表示数据库中一个人的信息,第1个元素是姓名,第2个是年龄,根据上述内容编写一个列表:
edward=['Edward Gumby',42]
john=['John Smith',50]
database=[edward,john] #结果出现 [['Edward Gumby', 42], ['John Smith', 50]]
Python中还有一个名为容器(container)的数据结构,它是包含其它对象的任意对象,序列和映射是两类主要的容器。容器集合(set)既不是序列也是不是映射。
2.2 通用序列操作
2.2.1 索引
序列中的都有编号,从0开始递增,可以通过编号来访问这些元素
greeting='hello'
greeting[0] #结果显示第一个元素,'h'
使用负数索引时,是从右边开始计数,即最后一个。
greeting[-1] #结果为'o',即最后一个元素。
不能超过元素个数范围
greeting[5] #会报错,因为这个位置不存在元素
<pre name="code" class="python">greeting[-6] 同上
如果是调用返回同一个序列,可以直接对返回结果进行索引操作。
fourth=input('year:')[3] #只对输入年份的末位数字感兴趣
year:2005
fourth #结果显示为'5'
#根据给定的年月日以数字形式打印出日期
months=[
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
]
#以1~30的数字作为结尾的列表
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=months[month_number-1]
ordinal=day+endings[day_number-1]
print(month_name+' '+ordinal+','+year)
2.2.2 分片
分片是访问一定范围内的元素,通过冒号相隔的两个索引来实现。
tag='<a href="http://www.python.org">python web site</a>'
tag[9:30] #结果为'http://www.python.org',显示编号9到编号30的元素。
tag[32:-4] #运行结果'python web site',显示编号32起至倒数第4个元素。
分片的操作需要提供两个索引作为边界,第1个索引的元素是包含在分片内的,第2个不包含。
1.优雅的捷径
如果需要访问最后三个,可以有如下操作
numbers=[1,2,3,4,5,6,7,8,9,10]
numbers[3:6] #运行结果[4, 5, 6]
numbers[-3:-1] #这个结果不是想要的,最后一位元素无法显示,只显示[8, 9]
numbers[-3:0] #显示[],如果在分片中最左边的索引比右边的晚出现在序列中,结果就是空的序列。
numbers[-3:] #最后一个索引空置就可以出现正确结果了,[8,9,10]
numbers[:3] #同样适用于序列开始的元素,结果显示[1,2,3]
numbers[:] #复制整个序列。
#对http://www.something.com形式的URL进行分割
url=input('please enter the URL:')
domain=url[11:-4]
print("domain name:"+domain) #提取域名
2.更大的步长。
步长(step lenth)参数通常是隐匿设置的,在普通的分片中,步长是1,分片操作就是按照这个步长逐个遍历序列的元素,然后返回开始和结束点之间的所有元素。
numbers=[1,2,3,4,5,6,7,8,9,10] #中间运行了其它程序,所以要重新定义一遍numbers
numbers[0:10:1] #运行结果为[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],定义了步长为1
numbers[0:10:2] #运行结果为[1,3,5,7,9]
numbers[3:6:3] #运行结果为[4]
numbers[::4] #运行结果为[1,5,9]
numbers[8:3:-1] #步长可以是负数,即从右向左提取元素,运行结果[9,8,7,6,5]
注意:
- 步长不能为0
- 开始点的元素(最左边的)包括在结果之中,结束点的不在
- 当使用负数为步长时,必须让开始点(开始索引)大于结束点。
2.2.3 序列相加
通过加号可以进行序列的连接操作,两种同一类型的序列才能进行连接。
[1,2,3]+[4,5,6,7] #运行结果[1, 2, 3, 4, 5, 6, 7],跟两个序列元素数量无关
'hello,'+'world!'
"hello,"+'world!'
'hello,world!' #这三个都可以正确显示'hello,world!'
"hello,"+"1,2,3" #显示'hello,1,2,3',这里的1,2,3是字符
[1,2,3]+'hello'#报错,不是同一类型
2.2.4 乘法
用数字X乘以一个序列会生成新的序列,在新序列中,原来的数列会重复X次。
'python'*5 #运行结果'pythonpythonpythonpythonpython'
[42]*5 #运行结果[42, 42, 42, 42, 42],这里的[42]是序列而不是数字。
'42'*5 #运行结果'4242424242',这里的‘42’表示字符串
[1,2,3]*5 #运行结果 [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
None、空列表和初始化
空列表可以用两个中括号表示[],如果 想要生成一个占用10个元素的空间,却不包含任何内容,就要用到None.
[]*5 #运行结果显示[]
[None]*5 #运行结果[None, None, None, None, None],这里的None首字母一定要大写,否则报错
[]+[] #运行结果[]
[]+[1,2,3] #运行结果[1,2,3]
[]+[None] #运行结果[None]
序列(字符串)乘法示例
#以正确的宽度在居中的“盒子”内打印一个句子
sentence=input("setence:")
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-6)+ '+') #<span style="color:#6633FF;">修改了原来的语句才合适,版本差异?原来是-2,导致会长一截</span>
print(' '*left_margin+'|'+' '*text_width+'|')
print(' '*left_margin+'|'+sentence+'|')
print(' '*left_margin+'|'+' '*text_width+'|')
print(' '*left_margin+'+'+'-'*(box_width-6)+'+')
print
新版本里面应该有改动,导致按照原语句运行无法形成整齐的方格,原因待研究。2.2.5 成员资格
检查一个值是否在序列中,可以用in运算符。这个运算符是布尔运算符,检查条件是否为真,若为真(布尔值),返回True,假则返回False。
permissions='rw'
'w' in permissions #运行结果True
's' in permissions #运行结果Falseusers=['mlh','foo','bar']
input('enter your user name:') in users
enter your user name:mlh #运行结果 True
subject='$$$ Get rich now!!! $$$'
'$$$' in subject #运行结果 True
示例,查看用户输入的用户名和PIN码是否存在于数据库
#检查用户名和PIN码
database=[
['albert','1234'],
['dilbert','4242'],
['smith','7524'],
['jones','9843']
]
username=input('user name:')
pin=input('PIN code:')
if[username,pin] in database: print ('Access granted')
2.2.6 长度、最小值和最大值
内建函数len,min和max.
Len:返回序列中所包含元素的数量。
min:返回最小的元素
max:返回最大的元素
numbers=[100,34,678]
len(numbers) #序列中共有3个元素,所以返回值为3
max(numbers) #返回值678
min(numbers) #返回值34
max(2,3) #也可以直接使用,3<pre name="code" class="python">min(9,3,2,5) #返回2
max[2,3] #报错
2.3 列表:Python的苦力
2.3.1 list函数
字符串不能像列表一样被修改,根据字符串创建列表很有用。
list('hello') #返回值['h', 'e', 'l', 'l', 'o']
list([1,2,3]) #返回值[1, 2, 3],list函数适用于所有类型的序列
2.3.2 基本的列表操作
1.改变列表:元素赋值
x=[1,1,1]
x[1]=2
x #返回值[1, 2, 1],x已改变
2.删除元素(del)
names=['Alice','Beth','Cecil','Dee-Dee','Earl']
del names[2]
names #返回值['Alice', 'Beth', 'Dee-Dee', 'Earl'],已删除索引标记为2的元素'Cecil'.
3.分片赋值
name=list('Perl')
name #运行结果['P', 'e', 'r', 'l']
name[2:]=list('ar')
name #运行结果['P', 'e', 'a', 'r'],从第3个元素起变成a,r
name[2:]=list('ars')
name #运行结果['P', 'e', 'a', 'r','s'] #长度可以不相等
numbers=[1,5]
numbers[1:1]=[2,3,4] #在第二个位置插入序列
numbers #运行结果[1, 2, 3, 4, 5]
numbers[1:4]=[] #删除元素
numbers #返回值[1,5]
2.3.3 列表方法
方法是一个与某些对象有紧密联系的函数。方法的调用形式为:对象.方法(参数)
append | 在列表末尾追加新的对象 |
count | 统计某个元素在列表中出现的次数 |
extend | 在列表末尾一次性追加另一个序列中的多个值 |
index | 从列表中找出某个值第一个匹配项的索引位置 |
insert | 将对象插入到列表中 |
pop | 移除列表中的一个元素(默认最后一个),并返回该元素的值 |
remove | 移除列表中某个值的第一个匹配项 |
reverse | 将列表中的元素反向存放 |
reversed | 对一个序列进行反向迭代 |
sort | 在原位置对列表进行排序 |
sorted | 获取已排序列表副本 |
高级排序 | 按特定方式进行排序 |
1.append
lst=[1,2,3] #第一个字符为字母l,变量名第一个不能为数字,也不能用list,一旦用了内建函数作为变量名,它就不能被调用了
lst.append(4)
lst #返回值[1, 2, 3, 4]
2.count
['to','be','or','not','to','be'].count('to') #'to'在列表中出现的次数,返回2
x=[[1,2],1,1,[2,1,[1,2]]]
x.count(1) #返回值为2
x.count([1,2]) #返回值为1
3.extend
a=[1,2,3]
b=[4,5,6]
a.extend(b)
a #返回值[1, 2, 3, 4, 5, 6]
a=[1,2,3]
b.extend(a)
b #返回值[4, 5, 6, 1, 2, 3]
这个用法类似于序列相加,但是序列相加不改变原变量值。如果想要改变变量a的值,需要加上一条a=a+b
也可以用分片赋值,
a=[1,2,3]
b=[4,5,6]
a[len(a):]=b
a #返回[1, 2, 3, 4, 5, 6],分片赋值真是万能的啊!
4.index
knights=['we','are','the','knights','who','say','ni']
knights.index('who') #返回值4
knights.index('herring') #提示错误,herring不在list中
5.insert
numbers=[1,2,3,4,5,6,7]
numbers.insert(3,'four')
numbers #返回值[1, 2, 3, 'four', 4, 5, 6, 7],'four'被插入到索引为3的位置上
万能的分片赋值也可以做到。
numbers=[1,2,3,4,5,6,7]
numbers[3:3]=['four']
nmbers #可读性不如insert。
6.pop
x=[1,2,3]
x.pop() #这里会先返回值3,默认移除最后一个元素
x #返回值[1, 2],x序列已变。
x.pop(0) #返回值1
x #返回值[2]。pop是唯一一个既能修改列表又返回元素值(除了None)的列表方法
用pop方法可以实现一种常见的数据结构——栈。栈的原则是后进先出(LIFO).栈的操作有两个,入栈(push)和出栈(pop),python中没有入栈,可以通过append方法来代替。
x=[1,2,3]
x.append(x.pop())
x #返回值[1, 2, 3],入栈的是刚出栈的值,结果还是原来的栈。
7.remove
x=['to','be','or','not','to','be']
x.remove('be') #没有返回值,直接修改
x #返回值['to', 'or', 'not', 'to', 'be'],第一个匹配的'be'已经被移除。
x.remove('bee') #报错,'bee'不存在。
8.reverse
x=[1,2,3]
x.reverse()
x #返回值[3, 2, 1]
如果需要对一个序列进行反向迭代,可以会用reversed函数
x=[1,2,3]
reversed(x) #返回值是<list_reverseiterator object at 0x00000000035D7B70>,reversed函数返回的是一个迭代器对象
list(reversed(x)) #返回值[3, 2, 1],用list函数把它转换成列表。
9.sort
x=[4,6,2,1,7,9]
x.sort()
x #返回值[1, 2, 4, 6, 7, 9],按顺序排列
sort是没有返回值的,因此下面的做法是错误的
x=[4,6,2,1,7,9]
y=x.sort()
print(y) #返回值None,sort没有返回值
x #返回值[1, 2, 4, 6, 7, 9],被排序了
正确的做法如下
x=[4,6,2,1,7,9]
y=x[:] #先对y赋值,把x列表复制进y
y.sort()
x #返回值[4, 6, 2, 1, 7, 9]
y #返回值[1, 2, 4, 6, 7, 9]
复制整个列表不能用简单的赋值,
x=[4,6,2,1,7,9]
y=x
y.sort()
x #返回值[1, 2, 4, 6, 7, 9]
y #返回值[1, 2, 4, 6, 7, 9]
获取已排序列表副本还可以用sorted函数
x=[4,6,2,1,7,9]
y=sorted(x)
y #返回值[1, 2, 4, 6, 7, 9]
x #返回值[4, 6, 2, 1, 7, 9]
sorted的返回值总是返回一个列表
sorted('python') #返回值['h', 'n', 'o', 'p', 't', 'y']
10.高级排序
python 3.4中cmp函数已被删除。
其它的高级排序方法
x=['aardvark','abalone','acme','add','aerate']
x.sort(key=len) #按长度进行排序,如果有长度一样的单词,会保持原来位置
x #返回值['add', 'acme', 'aerate', 'abalone', 'aardvark']
x=[4,6,2,1,7,9]
x.sort(reverse=True) #这里的True首字母必须大写,否则报错
x #返回值[9, 7, 6, 4, 2, 1]
2.4 元组:不可变序列
元组也是一种序列,不能修改(字符串也是这样)。用逗号分隔一些值就自动创造了元组,元组(大部分时候)通过圆括号括起来的,空元组就是()
1,2,3 #返回值(1, 2, 3)
a,b,c #报错字符必须要用引号
'a','b','c' #返回值('a', 'b', 'c')
42, #返回一个值的元组(42,)
42 #返回42,这不是一个元组
(42) #返回42,也不是元组,创建元组的关键在逗号,跟括号无关
3*(40+2) #返回值126,就是数值运算
3*(40+2,) #返回值(42, 42, 42),先进行运算后变成元组
3*(40,+2) #返回值(40, 2, 40, 2, 40, 2)
2.4.1 tuple函数
跟list函数基本一样:以一个序列作为参数并把它转换为元组。
tuple([1,2,3]) #返回值(1, 2, 3)
tuple('abc') #返回值('a', 'b', 'c')
tuple((1,2,3)) #返回值(1, 2, 3),本身就是元组,返回自身
2.4.2 基本元组操作
元组只有创建元组和访问元组。
x=1,2,3
x[1] #返回值2,
x[0:2] #返回值(1, 2),元组的分片还是元组
2.4.3 那么,意义何在
大部分时候,列表可以满足对序列的所有需求。由于以下两个原因,元组无可替代
- 元组可以在映射(和集合的成员)中当作键使用,列表不行
- 元组作为很多内建函数和方法的返回值存在。