1. 序列
1.1. 序列概览
在Python中,最基本的数据结构是序列(sequence),序列中的每一个元素被分配一个序号——即元素的位置,也成为索引,从0开始计数。Python中有6种内建的序列:列表、元组、字符串、Unicode字符串、buffer对象、xrange对象。
所谓“序列概览”讲的是所有序列类型都通用的操作。
列表和元组的主要区别:列表可以修改,元组则不能。
下面就是一个序列的例子:
ylh = ['yangliehui',28]
序列也可以包含其他序列:
>>> ylh = ['yangliehui',28]
>>> zs = ['zhangsan',30]
>>> names = [ylh,zs]
>>> names
[['yangliehui', 28], ['zhangsan', 30]]
1.2. 通用序列操作
1.2.1. 索引
序列中所有的编号都是从0开始的,比如下面的字符串就是为字符组成的序列。
>>> greeting = 'Hello'
>>> greeting[0]
'H'
序列的索引可以是从左向右,此时第一个是0,往右加1;可以可以是从右向左,最右边-1开始,往左减1;如下:
>>> greeting = 'Hello!'
>>> greeting[-1]
'!'
序列字面值可以直接使用索引而不需要一个变量引用(这适用于其他序列而不仅限于字符串),如下:
>>> 'Hello!'[0]
'H'
>>> 'Hello!'[-1]
'!'
也可以直接对返回结果操作:
>>> year = raw_input('Year=')[3]
Year=2017
>>> year
'7'
1.2.2. 分片
与索引类似,索引用来访问单个元素,而分片用来访问一定范围内的元素。格式如下:
[参数1:参数2]:参数1表示要提取的第一个元素的编号,第二个参数表示分片之后剩余部分中第一个元素的标号。
>>> str = 'abcdefg'
>>> str[1:5]
'bcde'
上面的代码可以用下图表示:
>>> str = 'abcdefg'
>>> str[-6:-2]
'bcde'
上面的代码可以用下图表示:
我们要注意下面的情况,如果自左向右取数,索引7指向的元素并不存在,但却是在最后一个元素之后,是没有问题的。但是如果从结尾自右向左取数,显然第二个参数写-1或写0都是不对的。尤其例子中[-6:0]的写法,只要顺序写反了都会返回空字符串。
>>> str = 'abcdefg'
>>> str[1:7]
'bcdefg'
上面的代码可以用下图表示:
>>> str = 'abcdefg'
>>> str[-6:-1]
'bcdef'
>>> str[-6:0]
''
上面的代码可以用下图表示:
那么上述描述的情况就无解了吗?其实我们可以有另一种写法,空一个参数:
>>> str = 'abcdefg'
>>> str[-6:]
'bcdefg'
>>> str[1:]
'bcdefg'
两个参数都写空也是可以的,这样将会返回整个序列:
>>> str = 'abcdefg'
>>> str[:]
'abcdefg'
现在介绍分片的第三个参数,步长,看一段程序:
>>> numbers=[1,2,3,4,5,6,7,8,9,10]
>>> numbers[0:10:1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> numbers[0:10:2]
[1, 3, 5, 7, 9]
以上就是步长,当步长为2时会跳过一个元素;
步长不能为0,但是步长可以为负数,这时从从右向左取数:
>>> numbers=[1,2,3,4,5,6,7,8,9,10]
>>> numbers[::-1]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> numbers[::-2]
[10, 8, 6, 4, 2]
但这里要注意,如果步长为负数,那么第一第二个参数提取元素的顺序也是倒序的,如下:
>>> numbers=[1,2,3,4,5,6,7,8,9,10]
>>> numbers[8:3:-1] #我们看到参数的顺序是先8后3
[9, 8, 7, 6, 5]
>>> numbers[10:0:-2] #我们看到参数的顺序是先10后0
[10, 8, 6, 4, 2]
>>> numbers[0:10:-2] #反过来试试?发现顺序错误,返回空字符串
[]
>>> numbers[5::-2]
[6, 4, 2]
>>> numbers[:5:-2]
[10, 8]
1.2.3. 序列相加
序列相加即是连接操作:
>>> [1,2,3]+[4,5,6]
[1, 2, 3, 4, 5, 6]
>>> 'Hello,' + 'World!'
'Hello,World!'
>>> [1,2,3] + 'World!'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list
两种类型相同的序列才可以相加,所有上述[1,2,3]+’World!’报错。
1.2.4. 序列乘法
我们先来看一个例子:
>>> 'python'*5
'pythonpythonpythonpythonpython'
>>> [23]*4
[23, 23, 23, 23]
None是一个Python的内建值,表示“什么也没有”。初始化一个长度为10的列表:
>>> sequence = [None] * 10
>>> sequence
[None, None, None, None, None, None, None, None, None, None]
1.2.5. 成员资格
in运算符:检查一个值是否在序列中;
>>> permissions = 'rw'
>>> 'w' in permissions
True
>>> 'x' in permissions
False
>>> user = ['mlh','foo','bar']
>>> raw_input('Enter your user name:') in user
Enter your user name:mlh
True
>>> subject = '$$$ Get rich now!!! $$$'
>>> '$$$' in subject
True
对于字符串,in可以查找子字符串:
>>> str = 'hello'
>>> 'hel' in str
True
1.2.6. 长度、最小值、最大值
len、min、max函数。
>>> numbers=[100,34,678]
>>> len(numbers)
3
>>> max(numbers)
678
>>> min(numbers)
34
>>> max(2,3)
3
>>> min(9,3,4,5)
3
1.3. 序列涉及到的一些内建函数
1.3.1. reversed(seq)
对序列反向迭代。
与列表的reverse()方法不同,这个函数返回的是一个迭代器对象,对迭代器的使用这里不涉及,后续会有讲解。
>>> x = [1,2,3]
>>> y = reversed(x)
>>> list(y)
[3, 2, 1]
1.3.2. sorted(seq)
返回已排序的包含seq所有元素的列表。
与列表的sort()方法不同,列表sort方法是在原列表中修改,并且不会有返回值。而该函数不会对原列表修改,并且返回一个已经排序的列表副本:
>>> x = [6,5,2,8,9,2]
>>> y = sorted(x)
>>> x
[6, 5, 2, 8, 9, 2]
>>> y
[2, 2, 5, 6, 8, 9]
并且这个函数适用于所有的序列类型,并且总是返回一个列表:
>>> sorted('hello')
['e', 'h', 'l', 'l', 'o']
>>> sorted([4,1,2,7,0])
[0, 1, 2, 4, 7]
>>> sorted((4,1,2,6,1))
[1, 1, 2, 4, 6]
2. 列表
2.1. 列表的基础操作
列表是可变的——可以改变列表的内容。
2.1.1. 创建列表
list函数:创建列表。适用于所有的序列类型,而不只是字符串。下面只是以字符串举例。由于字符串不能修改,所以可以根据字符串创建列表。利用list函数可以实现。
>>> list('hello')
['h', 'e', 'l', 'l', 'o']
>>> p1 = 'hello'
>>> list(p1)
['h', 'e', 'l', 'l', 'o']
>>> p3 = (432,643,745)
>>> list(p3)
[432, 643, 745]
与之相反操作的函数为join。把列表转换为字符串:
>>> list_str = list('hello')
>>> ''.join(list_str)
'hello'
2.1.2. 改变列表
>>> x = [1,1,1]
>>> x[1] = 2
>>> x
[1, 2, 1]
2.1.3. 删除元素
del语句:
>>> names = ['zhangsan','lisi','yangliehui']
>>> del names[1]
>>> names
['zhangsan', 'yangliehui']
2.1.4. 分片赋值
>>> name = list('yangliehui')
>>> name
['y', 'a', 'n', 'g', 'l', 'i', 'e', 'h', 'u', 'i']
>>> name[7:]=list('yan')
>>> name
['y', 'a', 'n', 'g', 'l', 'i', 'e', 'y', 'a', 'n']
在上面的例子中,name[7:]=’yan’ 这样写也会是同样的结果,因为string也是序列类型,当把string作为参数进行分片赋值给列表时会把字符串作为列表来处理,自动转换为列表。只是使用list函数转换一下更易读。看如下的例子:
>>> number = [None]*10
>>> number
[None, None, None, None, None, None, None, None, None, None]
>>> number[:] = '0123456789'
>>> number
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
即使没有对’0123456789’做list转换,同样可以作为列表通过分片赋值。
分片赋值的好处是可以使用与原序列不等长的序列将分片替换:
>>> name = list('ylh')
>>> name[0:] = list('yangliehui')
>>> name
['y', 'a', 'n', 'g', 'l', 'i', 'e', 'h', 'u', 'i']
上面的例子中,name有三个字符的序列,替换为了十个字符的序列。
还可以插入新的元素:
>>> numbers = [1,5]
>>> numbers[1:1] = [2,3,4]
>>> numbers
[1, 2, 3, 4, 5]
还可以删除元素:
>>> numbers
[1, 2, 3, 4, 5]
>>> numbers[1:4] = []
>>> numbers
[1, 5]
还可以还步长配合使用:
>>> number = [1,2,3,4,5,6,7,8,9,10]
>>> number[::2] = ['a','b','c','d','e']
>>> number
['a', 2, 'b', 4, 'c', 6, 'd', 8, 'e', 10]
2.2. 列表常用方法
2.2.1. append
列表末尾加新的对象;
>>> num = [1,2,3]
>>> num.append(4)
>>> num
[1, 2, 3, 4]
>>> str = ['a','b','c']
>>> str.append('d')
>>> str
['a', 'b', 'c', 'd']
>>>
>>> num.append('e')
>>> num
[1, 2, 3, 4, 'e']
注意可以追加不同类型的对象到列表中。
append是在原列表基础上修改列表内容。
2.2.2. count
统计某个元素在列表中出现的次数。
>>> ['a','a','b','c'].count('a')
2
>>> x = [[1,2],1,1,[2,1,[1,2]]]
>>> x.count(1)
2
>>> x.count([1,2])
1
2.2.3. extend
在列表末尾追加另一个序列中的多个值。
>>> a = [1,2,3,4]
>>> b = [5,6,7,8]
>>> a.extend(b)
>>> a
[1, 2, 3, 4, 5, 6, 7, 8]
它与原始的连接操作不同之处在于extend修改了被扩展的列表,而连接则返回一个全新的列表。
>>> a = [1,2,3,4]
>>> b = [5,6,7,8]
>>> a + b
[1, 2, 3, 4, 5, 6, 7, 8]
>>> a
[1, 2, 3, 4]
可以看到a的值并没有变化。
当然我们也可以这样做,但是这只是创建了一个包含a和b的新列表,并重新赋给了a,不是一个原位置操作,不会修改原来的列表:
>>> a = a + b
>>> a
[1, 2, 3, 4, 5, 6, 7, 8]
所以效率不如extend。
如果要实现和extend一样的原位置操作,可以如下:
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a[len(a):] = b
>>> a
[1, 2, 3, 4, 5, 6]
这样做的缺点是可读性差,不如使用extend。
2.2.4. index
某个值第一个匹配项的索引位置:
>>> names = ['zhangs','lis','ylh','wangw','ylh','jim']
>>> names.index('ylh')
2
当没有找到时会报错:
>>> names.index('abc')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 'abc' is not in list
2.2.5. insert
insert(index,object) index表示对象插入后在新列表中的索引位置。这种方式同样也是修改了现有的列表,而不是创建新的列表。
>>> number = [1,2,3,4,5,6,7,8]
>>> number.insert(3,'ins')
>>> number
[1, 2, 3, 'ins', 4, 5, 6, 7, 8]
实现同样的功能,我们也可以使用分片:
>>> number = [1,2,3,4,5,6,7,8]
>>> number[3:3] = ['ins']
>>> number
[1, 2, 3, 'ins', 4, 5, 6, 7, 8]
注意,插入的必须是列表类型。 且可读性没有insert方法好。
2.2.6. pop
注意:它是唯一一个既能修改列表又返回新元素值(除了None)的列表方法
pop方法类似入栈出栈中的出栈。当调用pop时返回最上面的列表元素,并修改了原来的原来的列表。如下:
>>> number = [1,2,3]
>>> number.pop()
3
>>> number
[1, 2]
Python中并没有单独的入栈列表方法,但我们可以使用append来代替:
>>> number.append(3)
>>> number
[1, 2, 3]
下面的例子中,程序先出栈返回3并修改了列表为[1,2],随后又出栈了出栈时返回的[3]。 所以得到的还是原来的列表。
>>> number
[1, 2, 3]
>>> number.append(number.pop())
>>> number
[1, 2, 3]
所以上面append和pop方法配合使用,实现了栈的结构——后进先出。
其实pop方法还可以有参数的,参数表示要移除的元素在列表中的索引位置,如下:
>>> number = [1,2,3,4,5,6]
>>> number.pop(2)
3
>>> number
[1, 2, 4, 5, 6]
因此如果我们要实现一个queue,即先进先出,有以下两种方法:
1. insert(0,x) 和 pop() 配合使用:
>>> number = []
>>> number.insert(0,0)
>>> number.insert(0,1)
>>> number.insert(0,2)
>>> number.pop()
0
>>> number.pop()
1
>>> number.pop()
2
>>> number
[]
- append 和 pop(0)配合使用:
>>> number = []
>>> number.append(0)
>>> number.append(1)
>>> number.append(2)
>>> number.pop(0)
0
>>> number.pop(0)
1
>>> number.pop(0)
2
>>> number
[]
2.2.7. remove
移除列表中某个值的第一个匹配项:
>>> x = ['aaa','bb','aaa','cc']
>>> x.remove('aaa')
>>> x
['bb', 'aaa', 'cc']
>>> x.remove('dd')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list
只会移除第一个。并且当找不到参数内的元素时会提示错误。
它与pop不同的是,remove并不会返回被移除的元素值,它是没有返回值的。
相同的是,都在原列表上修改值;
2.2.8. reverse
反向存放。
>>> x = [1,2,3,4]
>>> x.reverse()
>>> x
[4, 3, 2, 1]
原列表上修改,无返回值。
2.2.9. sort
在原位置上对列表进行排序。并不是创建一个已排序的副本。该方法也没有返回值。
>>> x = [4,2,6,8,1,3,9]
>>> x.sort()
>>> x
[1, 2, 3, 4, 6, 8, 9]
关于排序的高级应用:
sort([func])
func——指定比较函数,按照该函数的方法进行排序。
这个指定的函数可以自建,比如我们定义一个函数compare(x,y),实现比如当x>y时返回1,当x
>>> x = [3,1,4,6,1,5,2,8]
>>> x.sort(cmp)
>>> x
[1, 1, 2, 3, 4, 5, 6, 8]
sort([key or reverse])
参数key与cmp类似,需要提供一个排序过程中使用的函数。该函数不能直接确定对象的大小,而是为每个元素创建一个键,然后所有元素根据键来排序:
>>> x = ['aaaaaa','aa','a','aa']
>>> x.sort(key=len)
>>> x
['a', 'aa', 'aa', 'aaaaaa']
以元素的len为键,然后进行排序。
参数reverse,指定是否反向排序。
>>> x = [2,5,1,7,3,9,2,5]
>>> x.sort(reverse=False)
>>> x
[1, 2, 2, 3, 5, 5, 7, 9]
>>> x.sort(reverse=True)
>>> x
[9, 7, 5, 5, 3, 2, 2, 1]
3. 元组
序列的一种,不能修改。(其实字符串也是这样的)
3.1. 创建元组
>>> #直接逗号分隔
... 1,2,3
(1, 2, 3)
>>> #圆括号
... (1,2,3)
(1, 2, 3)
>>> #空元组
... ()
()
>>> #创建一个值的元组,我们发现必须要在元素后面加一个逗号
... 23,
(23,)
>>> (23)
23
>>> (23,)
(23,)
逗号的作用,一个逗号,结果千差万别:
>>> 3*(40+2)
126
>>> 3*(40+2,)
(42, 42, 42)
3.2. tuple函数
与list函数类似,把序列类型值作为参数返回的是元组。
>>> tuple('abc')
('a', 'b', 'c')
>>> tuple([1,2,4])
(1, 2, 4)
>>> tuple((1,2,3))
(1, 2, 3)
元组可以使用与列表同样的分片操作,元组的分片还是元组,就像列表的分片还是列表一样。
>>> x = (1,2,3,4)
>>> x[1:3]
(2, 3)