在上一节里面我们讲到了变量。但是,生活中也并不是哪里的数据都适合使用变量来存储。比如,一些成堆出现的数据。那么,本节就要引入一个新的概念:数据结构。
所谓数据结构,实际上就是通过某种方式(比如给元素编号),组织在一起的数据集合。在Python中,最基本的数据结构就是序列(sequence)。序列中的每一个元素都被分配一个序号,也就是元素的位置,称之为索引。但是,Python的索引是从0开始,而不是我们习惯的从1开始。
Python包括6中内建序列:列表(list),元组(tuple),字符串(string),Unicode字符串(Unicode string),buffer对象和xrange对象。本节只讨论列表和元组。
另外,序列中的元素也可以是一个序列,如:
>>> edward = ['Edward Gumby', 42]
>>> john = ['John Smith', 50]
>>> database = [edward, john]
>>> database
[['Edward Gumby', 42], ['John Smith', 50]]
通用序列操作
所有下序列类型都可以进行某些特定的操作。包括索引(indexing),分片(slicing),加(adding),乘(multiplying),成员资格以及迭代(iteration,本节不讲)。除此之外,Python还有计算序列长度,找出最大最小元素等内建函数。
索引
通过元素的编号来访问元素(从0开始,谨记!):
>>> name = 'TechZone'
>>> name[0]
'T'
>>> name[5]
'o'
由于是从0开始,于是索引0对应的就是第一个元素,索引6就是第五个元素。
当然,如果你不希望把这个序列赋值给一个变量,也可以直接进行操作:
>>> 'TechZone'[5]
'o'
亦或许,你想把序列中某一个元素赋值给一个变量,也是可以的:
>>> letter = 'TechZone'[5]
>>> letter
'o'
如果这个序列很长,也可以倒着数:
>>> 'Hello'[-1] #代表从结尾开始数的第一个
'o'
分片
和索引一样,分片是用来访问一段元素的。比如我想一次性访问序列的第3到第6个元素:
>>> name = 'TechZone'
>>> name[2:6]
'chZo'
需要注意的是,起始元素(冒号左边)是包含在内的,而终止元素(冒号右边)是不包含在内的。因此name[2:6]
实际上等价于name[2] + name[3] + name[4] + name[5]
。
如果我们要访问最后的三个元素怎么办呢?
当然可以使用常规的方法:
>>> name[5:8]
'one'
如果我们要从结尾开始访问呢?
>>> name[-3:-1]
'on'
由于终止元素不包含在分片里面,于是后面我们就访问不到。
改改试试:
>>> name[-3:0]
''
什么都没有返回!为什么会这样呢?
因为[0]
其实比[-3]
更先出现。那么起始元素比终止元素还大,从数学的角度来说,就是空集了。
难道真的没有办法这样访问吗?
并不是,看看这样:
>>> name[-3:]
'one'
把终止元素的位置留空,那么Python就会自动认为你要一直访问到最后元素,于是就把这个问题巧妙解决了。
当然,这个方法也可以这么用:
>>> name[:3]
'Tec'
>>> name[:]
'TechZone'
很好理解吧。
分片的步长
其实分片还有一个参数,我们刚刚并没有用,就是步长。步长的默认设置为1,意思就是挨个访问。比如:
>>> name[1:4]
'ech'
实际上等价于:
>>> name[1:4:1]
'ech'
如果步长改成2:
>>> name[1:4:2]
'eh'
你会发现检索的单位变成了2(也就是说,中间会跳过一个元素)
也许这么看,就好理解了:
>>> nums = [1,2,3,4,5,6,7,8,9,10]
>>> nums[::1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> nums[::2]
[1, 3, 5, 7, 9]
>>> nums[::3]
[1, 4, 7, 10]
>>> nums[::4]
[1, 5, 9]
当然,步长不能够为0,但是可以为负数(倒过来检索):
>>> nums[::-1]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> nums[::-2]
[10, 8, 6, 4, 2]
>>> nums[::-3]
[10, 7, 4, 1]
>>> nums[::-4]
[10, 6, 2]
序列运算
相加
>>> [1,2,3]+[4,5,6]
[1, 2, 3, 4, 5, 6]
>>> 'TechZone'+'Harris'
'TechZoneHarris'
>>> [1,2,3]+'Harris'
'''
Traceback (most recent call last):
File "<pyshell#35>", line 1, in <module>
[1,2,3]+'Harris'
TypeError: can only concatenate list (not "str") to list
'''
相同类型的序列相加,实际上就是拼接起来。但是不同类型的序列是不能够相加的。
乘法
>>> 'Harris' * 5
'HarrisHarrisHarrisHarrisHarris'
>>> [1,2] * 10
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
也很好理解。
初始化
如果我想创建一个列表,作为占位符(暂时不用,但是以后要用的),那么可以用一对方括号[]
来表示。如果想创建一个拥有10个元素的列表占位符,那么该怎么办呢?
我们可以使用一些对于你来说没有意义的字符,比如0:
>>> space = [0] * 10
>>> space
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
不过这样的作法其实并不是十分稳妥,因为没准你找不出来这样的特殊的数字。那么这里介绍一个Python内建值:None
,表示什么都没有。那么我们的占位符就可以这样创建:
>>> space = [None] * 10
>>> space
[None, None, None, None, None, None, None, None, None, None]
成员资格
判断一个值是否在序列中,我们可以使用in
运算符。这种运算符不同于加减乘除,它会去检查我们的条件是否为真,若是,则返回True
,反之则返回False
。这样的运算符我们叫做布尔运算符,返回的这个值称之为布尔值。
>>> user = ['Harris', 'Mary','Scott']
>>> 'Harris' in user
True
>>> 'Jack' in user
False
长度、最值
>>> name = 'HarrisWilde'
>>> len(name) #序列长度
11
>>> len([1,2,3,4])
4
>>> max([1,3,2,13,6,5,8]) #最大值
13
>>> min([0.01, 0.02, 0.009, 0.015]) #最小值
0.009
列表
使用[]
括起来的序列集合就是列表。
list函数
使用list
函数来将序列转换为列表。
>>> list("TechZone")
['T', 'e', 'c', 'h', 'Z', 'o', 'n', 'e']
你还可以使用join
函数来把序列中所有的元素(的字符串表示)合并为一个新的字符串:
>>> seq = list("TechZone")
>>> '-'.join(seq)
'T-e-c-h-Z-o-n-e'
基本列表操作
元素赋值
为单个元素赋值:
>>> x = [0] * 3
>>> x[1] = 1
>>> x
[0, 1, 0]
删除元素
使用del
函数:
>>> x
[0, 1, 0]
>>> del x[2]
>>> x
[0, 1]
分片赋值
分片赋值可以实现一次性的批量赋值:
>>> x = list("python")
>>> x
['p', 'y', 't', 'h', 'o', 'n']
>>> x[4:] = '12'
>>> x
['p', 'y', 't', 'h', '1', '2']
而且还可以非等长替换:
>>> x
['p', 'y', 't', 'h', '1', '2']
>>> x[4:] = 'Lang'
>>> x
['p', 'y', 't', 'h', 'L', 'a', 'n', 'g']
因此,也可以间接地增加或删除元素:
>>> x[8:8] = '12' #在最后的不存在的位置增加
>>> x
['p', 'y', 't', 'h', 'L', 'a', 'n', 'g', '1', '2']
>>> x[4:8] = []
>>> x
['p', 'y', 't', 'h', '1', '2']
列表方法
append
此方法用于在列表后面追加元素:
>>> nums = [1,2,3]
>>> nums.append(4)
>>> nums
[1, 2, 3, 4]
count
此方法统计某个元素在列表中出现的次数:
>>> name = 'TechZone'
>>> name.count('e')
2
extend
此方法可以在末尾一次性追加多个值,并且更改原来的列表:
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a.extend(b)
>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[4, 5, 6]
index
此方法用于找出列表中某个值的第一个匹配元素的索引,若找不到则会返回错误:
>>> name = 'TechZone'
>>> name.index('e')
1
>>> name.index('a')
'''
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
name.index('a')
ValueError: substring not found
'''
insert
此方法用于将对象插入到列表中:
>>> nums = [1,2,3,5]
>>> nums.insert(3, 'four')
>>> nums
[1, 2, 3, 'four', 5]
pop
此方法用于移除列表中的最后一个元素,并且返回被移除元素的值:
>>> nums = [1,2,3,4]
>>> nums.pop()
4
>>> nums
[1, 2, 3]
pop方法是唯一一个既能修改列表又能返回元素值(除了None)的列表方法
remove
remove方法用于移除列表中的某个值的首个匹配项:
>>> words = ['a','friend','in','need','is','a','friend','indeed']
>>> words.remove('friend')
>>> words
['a', 'in', 'need', 'is', 'a', 'friend', 'indeed']
remove是一个没有返回值的原位置改变方法。和pop恰恰相反。
reverse
此方法将列表中的元素反向存放。
>>> x = [1,2,3]
>>> x.reverse()
>>> x
[3, 2, 1]
此方法也是不返回值,和remove一样。
如果需要对一个序列进行反向迭代,那么可以使用
reversed
函数。这个函数返回的是迭代器对象(iterator)。当然,使用list
函数把返回的对象转换成列表也是可行的:>>> x = [1,2,3] >>> list(reversed(x)) [3, 2, 1]
sort
此方法用于对列表进行原地排序。所谓原地排序,就是更改原来的列表,而不是返回一个已排序的副本。
>>> x = [4,5,3,6,2,5,1]
>>> x.sort()
>>> x
[1, 2, 3, 4, 5, 5, 6]
如果你想得到的恰恰是一个副本,想保留原来的列表,千万不要这么做:
>>> x = [4,5,3,6,2,5,1]
>>> y = x.sort() #错误的做法
>>> print(y)
None
因为sort
函数是不返回值的(实际上返回的是空值)。如果要实现这个功能,那么只能把原先x的副本赋给y,然后对y进行排序:
>>> x = [4,5,3,6,2,5,1]
>>> y = x
>>> y.sort()
>>> y
[1, 2, 3, 4, 5, 5, 6]
>>> x
[1, 2, 3, 4, 5, 5, 6]
你会发现,为何原来的x也被改变了呢?
原来,简单的等号赋值,会让x和y指向同一个对象。那么,我们使用分片的方法来赋值,就可以巧妙地躲开这个问题:
>>> x = [4,5,3,6,2,5,1]
>>> y = x[:]
>>> y.sort()
>>> y
[1, 2, 3, 4, 5, 5, 6]
>>> x
[4, 5, 3, 6, 2, 5, 1]
另外,还可以使用sorted
函数来获取已排序副本:
>>> x = [4,5,3,6,2,5,1]
>>> y = sorted(x)
>>> y
[1, 2, 3, 4, 5, 5, 6]
>>> x
[4, 5, 3, 6, 2, 5, 1]
sorted
函数可以用于任何序列,但是总会返回一个列表:
>>> sorted("TechZone")
['T', 'Z', 'c', 'e', 'e', 'h', 'n', 'o']
此函数默认是升序排序,如果我想降序,怎么办呢?
可以先排好序之后再反转,不过,有个更简便的方法:使用reverse参数。
>>> x = [4,5,3,6,2,5,1]
>>> x.sort(reverse = False) #默认情况,就是不写参数的情况
>>> x
[1, 2, 3, 4, 5, 5, 6]
>>> x.sort(reverse = True) #应用reverse参数
>>> x
[6, 5, 5, 4, 3, 2, 1]
当然,此函数还可以进行更高级的排序,就是使用key
参数。所谓key,笔者认为就是排序参考关键词。默认是按照值的大小(若是字符串则比较其对应编码的大小),使用此参数,就可以实现别的参考值。
比如我想根据字符串长度来排序:
>>> string = ['TechZone','HarrisWIlde','Python','Programing']
>>> string.sort(key=len)
>>> string
['Python', 'TechZone', 'Programing', 'HarrisWIlde']
当然,两个参数也可以一起用:
>>> string = ['TechZone','HarrisWIlde','Python','Programing']
>>> string.sort(key=len, reverse=True)
>>> string
['HarrisWIlde', 'Programing', 'TechZone', 'Python']
这两个参数对于sorted()
都有效。