Python序列类似于其他语言中的数组,但功能要强大很多。
Python中常用的序列结构有列表、元组、字符串,字典、集合以及range等对象也支持很多类似的操作。
列表、元组、字符串支持双向索引,第一个元素下标为0,第二个元素下标为1,以此类推;最后 一个元素下标为-1,倒数第二个元素下标为-2,以此类推。
python 常见序列对比:
比较项 | 列表 | 元组 | 字典 | 集合 |
---|---|---|---|---|
类型名称 | list | tuple | dict | set |
定界符 | 方括号[] | 圆括号() | 大括号{} | 大括号 {} |
是否可变 | 是 | 否 | 是 | 是 |
是否有序 | 是 | 是 | 否 | 否 |
是否支持下标 | 是(使用序号作为 下标) | 是(使用序号作 为下标) | 是(使用“键”作为下标) | 否 |
元素分隔符 | 逗号 | 逗号 | 逗号 | 逗号 |
对元素形式的要求 | 无 | 无 | 键:值 | 必须可哈希 |
对元素值的要求 | 无 | 无 | 必须可哈希 | 必须可哈希 |
元素是否可重复 | 是 | 是 | “键”不允许重 复,“值”可以重复 | 否 |
元素查找速度 | 非常慢 | 很慢 | 非常快 | 非常快 |
新增和删除元素速度 | 尾部操作快,其他位置慢 | 不允许 | 快 | 快 |
列表
- 列表是Python中内置有序、可变序列,列表的所有元素放在一对中括号“[]”中,并使用逗号分 隔开;
- 当列表元素增加或删除时,列表对象自动进行扩展或收缩内存,保证元素之间没有缝隙;
- 在Python中,一个列表中的数据类型可以各不相同,可以同时分别为整数、实数、字符串等基 本类型,甚至是列表、元组、字典、集合以及其他自定义类型的对象。
列表常用方法:
方法 | 说明 |
---|---|
lst.append(x) | 将元素x添加至列表lst尾部 |
lst.extend(L) | 将列表L中所有元素添加至列表lst尾部 |
lst.insert(index, x) | 在列表lst指定位置index处添加元素x,该位置后面的所有元素后移 一个位置 |
lst.remove(x) | 在列表lst中删除首次出现的指定元素,该元素之后的所有元素前移一 个位置 |
lst.pop([index]) | 删除并返回列表lst中下标为index(默认为-1)的元素 |
lst.clear() | 删除列表lst中所有元素,但保留列表对象 |
lst.index(x) | 返回列表lst中第一个值为x的元素的下标,若不存在值为x的元素则 抛出异常 |
lst.count(x) | 返回指定元素x在列表lst中的出现次数 |
lst.reverse() | 对列表lst所有元素进行逆序 |
lst.sort(key=None, reverse=False) | 对列表lst中的元素进行排序,key用来指定排序依据,reverse决定 升序(False)还是降序(True) |
lst.copy() | 返回列表lst的浅复制 |
-
lst.reverse()
,lst.sort()
>>> arr = list(range(10)) >>> arr [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> arr.reverse() #逆序 >>> arr [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] >>> arr.sort() #排序 >>> arr [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
浅复制,浅层次的复制,深复制
>>> arr = [1,2,3]
>>> arr = [1,2,3]
>>> arr1 = arr # 直接赋值 arr 和 arr1 共用内存 也就是说他们还是一个
>>> id(arr),id(arr1)
(2909054945928, 2909054945928)
>>> arr1[0] = 123
>>> arr #修改一个另一个也会改变
[123, 2, 3]
>>> arr2 = arr.copy() #浅复制,
>>> id(arr),id(arr2) #不共用内存了
(2909054945928, 2909053356424)
>>> arr2[0]=321 #修改一个另一个不会改变
>>> arr
[123, 2, 3]
>>> arr = [[1],2,3] #但是列表里面有可变序列时,可变序列改变 原来的也会改变
>>> arr2 = arr.copy()
>>> arr2[0].append(2)
>>> arr #在arr2里添加,arr里面也有了
[[1, 2], 2, 3]
>>> import copy #标准库copy
>>> arr
[[1, 2], 2, 3]
>>> arr3 = copy.deepcopy(arr) #深复制
>>> arr3
[[1, 2], 2, 3]
>>> arr3[0].pop() #arr3内层序列改变 arr不受影响
2
>>> arr
[[1, 2], 2, 3]
列表的索引:
- 下标索引
>>> arr = list(range(20))
>>> arr
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> arr[2]
2
>>> arr[0]
0
>>> arr[-2] #可以双向来
18
- 切片
- 切片适用于列表、元组、字符串、range对象等类型,但作用于列表时功能强大。可以使用切片来截取列表中的任何部分,得到一个新列表,也可以通过切片来修改和删除列表中部分元素,甚至可以通过切片操作为列表对象增加元素。
- 切片使用2个冒号分隔的3个数字来完成:[start: end: step]
- 第一个数字表示切片开始位置(默认为0)。
- 第二个数字表示切片截止(但不包含)位置(默认为列表长度)。
- 第三个数字表示切片的步长(默认为1),当步长省略时可以顺便省略后一个冒号
- 切片操作不会因为下标越界而抛出异常,而是简单地在列表尾部截断或者返回一个空列表,代码具有更强的健壮性。
>>> lit = list(range(5))
>>> lit
[0, 1, 2, 3, 4]
>>> lit[1:]
[1, 2, 3, 4]
>>> lit[:3]
[0, 1, 2]
>>> lit[:-3]
[0, 1]
>>> lit[1::2]
[1, 3]
>>> lit[:3:2]
[0, 2]
>>> lit[1::2]=[111,111]
>>> lit #可以使用切片来原地修改列表内容
[0, 111, 2, 111, 4]
>>> lit2 = lit[::] #切片返回的是列表元素的浅复制
>>> lit2
[0, 111, 2, 111, 4]
>>> lit2[1]=222
>>> lit
[0, 111, 2, 111, 4]
>>> lit2
[0, 222, 2, 111, 4]
列表推导式
列表推导式使用非常简洁的方式来快速生成满足特定需求的列表,代码具有非常强的可读性。
列表推导式语法形式为:
[expression for expr1 in sequence1 if condition1
for expr2 in sequence2 if condition2
for expr3 in sequence3 if condition3
...
for exprN in sequenceN if conditionN]
列表推导式在内部实际上是一个循环结构,只是形式更加简洁,例如:
>>> aList = [x*x for x in range(10)]
>>> aList
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
使用列表推导式实现嵌套列表的平铺:
>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
再如取偶数:
>>> arr = list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [i for i in arr if i%2==0]
[0, 2, 4, 6, 8]
>>> [i for i in range(30) if i%2==0]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]
元组
-
元组和列表类似,但属于不可变序列,元组一旦创建,用任何方法都不可以修改其元素。
-
元组的定义方式和列表相同,但定义时所有元素是放在一对圆括号“()”中,而不是方括号中。
列表和元组的区别
- 列表是动态数组,他们可变且可以重设长度(改变其内部元素的个数)。
- 元组是静态数组,他们不可变,且其内部数据一旦创建便无法改变。
- 元组缓存与Python运行时环境,这意味着我们每次使用元组时无须动态访问内核去分配内存。
列表和元组都可以接受混合类型。
>>> t = tuple(range(5)) >>> t (0, 1, 2, 3, 4) >>> t[1]=22 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment
生成器推导式
生成器推导式的结果是一个生成器对象。使用生成器对象的元素时,可以根据需要将其转化为列表或元组,也可以使用生成器对象
__next__()
方法或内置函数next()进行遍历,或者直接将其作为迭代器对象来使用。生成器对象具有惰性求值的特点,只在需要时生成新元素,比列表推导式具有更高的效率,空间占用非常少,尤其适合大数据处理的场合。
不管用哪种方法访问生成器对象,都无法再次访问已访问过的元素。
>>> g = (i for i in range(10))
>>> next(g)
0
>>> next(g)
1
>>> g.__next__()
2
>>> list(g)
[3, 4, 5, 6, 7, 8, 9]
>>> g = (i for i in range(10))
>>> 5 in g #找到5时 3已经遍历过了 所以 下面找不到3
True
>>> 3 in g #但会继续往下找 直到遍历了所有的元素
False
>>> 6 in g #所有6也在上次查找时被遍历了
False
>>> g = (i for i in range(10))
>>> 3 in g
True
>>> 5 in g
True
补充序列解包
序列解包是Python中非常重要和常用的一个功能,可以使用非常简洁的形式完成复杂的功能,提高了代码可读性,减少了代码输入量。
- 可以使用序列解包功能对多个变量同时赋值
>>> x, y, z = 1, 2, 3
>>> print(x,y,z)
1 2 3
>>> v_tuple = (4, 5, 6)
>>> x, y, z = v_tuple
>>> print(x,y,z)
4 5 6
>>> x, y, z = range(7,10)
>>> print(x,y,z)
7 8 9
- 更多的使用
>>> x, y, z = range(3) #可以对range对象进行序列解包
>>> x, y, z = iter([1, 2, 3]) #使用迭代器对象进行序列解包
>>> x, y, z = map(str, range(3)) #使用可迭代的map对象进行序列解包
>>> a, b = b, a #交换两个变量的值
>>> x, y, z = sorted([1, 3, 2]) #sorted()函数返回排序后的列表
>>> a, b, c = 'ABC' #字符串也支持序列解包
>>> x = [1, 2, 3, 4, 5, 6]
>>> x[:3] = map(str,range(5)) #切片也支持序列解包
>>> x
['0', '1', '2', '3', '4', 4, 5, 6]
- 序列解包遍历多个序列
>>> keys = ['a', 'b', 'c', 'd']
>>> values = [1, 2, 3, 4]
>>> for k, v in zip(keys, values):
print((k, v), end=' ')
('a', 1) ('b', 2) ('c', 3) ('d', 4)
- 对字典也适用
>>> s = {'a':1, 'b':2, 'c':3}
>>> b, c, d = s.items()
>>> b
('c', 3)
>>> b, c, d = s
>>> b
'c'
>>> b, c, d = s.values()
>>> print(b, c, d)
1 3 2
字典
-
字典是无序、可变序列。
-
定义字典时,每个元素的键和值用冒号分隔,元素之间用逗号分隔,所有的元素放在一对大括号“{}”中。
-
字典中的键可以为任意不可变数据,比如整数、实数、复数、字符串、元组等等。
globals()
返回包含当前作用域内所有全局变量和值的字典locals()
返回包含当前作用域内所有局部变量和值的字典
创建:
>>> a_dict = {'one':1,'two':2,'three':3} >>> a_dict {'one': 1, 'two': 2, 'three': 3} >>> keys = list('abcde') >>> values = list(range(4)) >>> dictionary = dict(zip(keys,values)) >>> dictionary {'a': 0, 'b': 1, 'c': 2, 'd': 3} >>> x = dict() >>> x #空字典 {} >>> d = dict(name='Dong', age=37) #使用键值创建字典 >>> d {'name': 'Dong', 'age': 37} >>> adict = dict.fromkeys(['name','age','sex']) #给定内容创建字典,值为空 >>> adict {'name': None, 'age': None, 'sex': None}
读取:
>>> a_dict = {'one':1,'two':2,'three':3} >>> a_dict['one'] #根据键获取值 1 >>> a_dict['name'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'name'
使用字典对象的get方法获取指定键对应的值,并且可以在键不存在的时候返回指定值
>>> a_dict.get('one') 1 >>> a_dict.get('name','None') #如果不存在 返回给定值 'None'
使用字典对象的
items()
方法可以返回字典的键、值对使用字典对象的
keys()
方法可以返回字典的键使用字典对象的
values()
方法可以返回字典的值>>> for k,g in a_dict.items(): #序列解包 ... print(k) ... print(g) ... one 1 two 2 three 3 >>> a_dict.keys() dict_keys(['one', 'two', 'three'])
添加,修改
当以指定键为下标为字典赋值时:
1)若键存在,则可以修改该键的值;
2)若不存在,则表示添加一个键、值对。
>>> a_dict {'one': 1, 'two': 2, 'three': 3} >>> a_dict['one'] = 11 #修改 >>> a_dict {'one': 11, 'two': 2, 'three': 3} >>> a_dict['four'] = 4 #添加 >>> a_dict {'one': 11, 'two': 2, 'three': 3, 'four': 4}
使用字典对象的update()方法将另一个字典的键、值对添加到当前字典对象。
>>> a_dict {'one': 11, 'two': 2, 'three': 3, 'four': 4} >>> b_dict = {'five': 5} >>> a_dict.update(b_dict) #将b_dict加到a_dict中 >>> a_dict {'one': 11, 'two': 2, 'three': 3, 'four': 4, 'five': 5}
- 使用
del
删除字典中指定键的元素 - 使用字典对象的
clear()
方法来删除字典中所有元素 - 使用字典对象的
pop()
方法删除并返回指定键的元素 - 使用字典对象的
popitem()
方法删除并返回字典中的一个元素
字典推导式
>>> s = {str(x):x for x in range(4)} >>> s {'0': 0, '1': 1, '2': 2, '3': 3}
注意 : 字典的键是可以哈希的,且键都是唯一的。不能为可变元素,如:列表。
集合
-
集合是无序、可变序列,使用一对大括号界定,元素不可重复,同一个集合中每个元素都是唯一的。
-
集合中只能包含数字、字符串、元组等不可变类型(或者说可哈希)的数据,而不能包含列表、字典、集合等可变类型的数据。
简单说集合就是没有值的字典。
>>> a = {3, 5} >>> a {3, 5} >>> a.add(4) >>> a {3, 4, 5} >>> a = {3,3,2,4,4} >>> a {2, 3, 4} >>> set(range(3,8)) {3, 4, 5, 6, 7} >>> set() set()
-
当不再使用某个集合时,可以使用
del
命令删除整个集合。集合对象的pop()
方法弹出并删除其中一个元素remove()
方法直接删除指定元素,clear()
方法清空集合。>>> a = {1,2,3,4} >>> a.pop() 1 >>> a.pop() 2 >>> a {3, 4} >>> a.add(2) >>> a {2, 3, 4} >>> a.remove(3) >>> a {2, 4} >>> a.clear() >>> a set() >>> del a >>> a Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'a' is not defined
Python集合支持交集,并集,差集等运算
>>> a_set = set(range(8,14)) >>> b_set = set(range(9)) >>> a_set | b_set #并集 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} >>> a_set.union(b_set) {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} >>> a_set & b_set #交集 {8} >>> a_set.intersection(b_set) {8} >>> a_set - b_set #差集 {9, 10, 11, 12, 13} >>> a_set.difference(b_set) {9, 10, 11, 12, 13} >>> {3} & {4} set() >>> {3}.isdisjoint({4}) #如果两个集合的交集为空,返回True True >>> x^y #对称差 {3, 5} >>> x.symmetric_difference(y) {3, 5}
子集,真子集,包含
>>> x = {1, 2, 3} >>> y = {1, 2, 5} >>> z = {1, 2, 3, 4} >>> x.issubset(y) #测试是否为子集 False >>> x.issubset(z) True >>> x < y #比较集合大小/包含关系 False >>> x < z #真子集 True >>> y < z False >>> {1, 2, 3} <= {1, 2, 3} #子集 True
-