Professional Documents
Culture Documents
2序列
2序列
2序列
主要内容
列表
元组
字典
集合
再谈内置方法
2
2.0 序列
一系列相关的对象 .
序列成员称为“元素” .
程序设计中常用的数据存储方式
• 几乎每种程序设计语言都提供了列表数据结构 , 如 : C 和 Basic 的一维、多维数组 .
3
常用的序列结构 : 列表 , 元组 , 字典 *, 字符串 , 集合 *,
range
可变 不可变
有序 列表 元组 **, 字符串
字典 , 集
无序
合
8
列表元素的修改
1) 通过下标修改序列中元素的值 .
2) 通过列表自身提供的方法增加 / 删除元素 .
序列在内存中的起始地址不变 , 但元素地址发生变化 .
9
列表方法 ( 操作 ) 说 明 (lst 为列表名 , 所有操作均针对 lst 进行 )
lst.append(x) 将元素 x 添加至列表 lst 尾部 ( 原地添加 )
lst.extend(L) 将列表 L 中所有元素添加至列表 lst 尾部
lst.insert(index, x) 在 lst 指定位置 index 处添加元素 x
lst.remove(x) 在 lst 中删除首次出现的元素 x
lst.pop([index]) 删除并返回 lst 指定位置的元素 , 默认删除列表尾部元
素
lst.clear() 删除列 lst 中所有元素 , 但保留列表对象 (Python2 不支
持)
lst.index(x) 返回 lst 中值为 x 的首个元素的下标
lst.count(x) 返回指定元素 x 在 lst 中的出现次数
lst.reverse() 对 lst 的所有元素进行原地逆序 ( 修改 lst 本身 )
lst.sort() 对 lst 的所有元素进行原地排序 ( 修改 lst 本身 )
lst.copy() 返回 +lst 的拷贝
列表相关的运算符: (Python2
* in 比较 (== <不支持
> 等 )) ,还有 += *=
(后面会讲)
2.1.1 列表的创建与删除
1. 使用 "=" 直接将一个列表赋值给变量
>>> a_list = ['a', 'b', 'mpilgrim', 'z', 'example']
>>> a_list = [] # 创建空列表
2. 使用 list() 将可迭代对象 ( 元组 , range 对象 , 字符串 , …) 转换为列表 .
# 将元组转换为列
表
# 将 range 对象转换为列
表
# 将字符串转换为列表
11
内置函数 range()
range([start, ] stop[, step])
函数返回一个整数序列的对象 ( 可迭代 ) ,而不是列表
参数 start 表示起始值(默认为 0 )
参数 stop 表示终止值(结果中不包括这个值),即左闭右开
区间 [start , stop )
参数 step 可选,表示步长默认为 1
可用 list() 函数将 range 对象转化为列表
>>> range(10)
range(0, 10)
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 12
3. 列表方法 list.copy() —— 浅拷贝
a [0]
[1] 1
[2]
c
2
b [0]
[1]
[2] 4
3
# 对于整数、实数、字符串等不可改变类型的数据,
修改列表 b 的元素不影响列表 a 13
浅拷贝 —— 只拷贝一层
a [0] 1
[0]
[1] [1] 2
[2]
3
# 修改列表 b 的元素影响了列表 a
b [0] 4
[0]
[1]
[1] 5
[2]
# 修改列表 a 的元素影响了列表 b
6
# 对于列表等可改变类型的对象,
修改列表 b 的元素会影响列表 a
深拷贝 deepcopy () -- 制造完整的副本
import copy
a = [[1,2,3],[4,5,6]]
b = copy.deepcopy(a)
a [0] 1
[0] [0] [0] b
[1] [1] 2 [1] [1]
[2] [2]
3
[0] 4 [0]
[1] [1]
[2] 5
[2]
6
#a 和 b 是独立的,对于列表等可改变类型的
对象,修改列表 b 的元素不会影响列表 a 15
不再使用时 , 可用 del 命令删除整个列表
若列表对象所指向的值不再有其它对象引用 , Python 将同时删除
该值 .
>>> del a_list
>>> a_list
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
a_list
NameError: name 'a_list' is not defined
删除列表对象 a_list 之后 , 该对象就不存在了 , 再次访问时将抛出
异常 "NameError".
16
2.1.2 列表元素的访问与计数
下标列表元素
若指定下标不存在抛出异常 IndexError
>>> aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17] >>> aList[15]
>>> aList[3] Traceback (most recent call last):
6 File "<pyshell#34>", line 1, in
>>> aList[3] = 5.5 <module>
>>> aList aList[15]
[3, 4, 5, 5.5, 7, 9, 11, 13, 15, 17] IndexError: list index out of range
17
指定元素下标
列表的 index 方法 : 获取指定元素首次出现的下标
L.index(value, [start, [stop]]) # return first index of value.
# Raises ValueError if the value is not
present.
start :查找的起始位置, stop :查找的结束位置
>>> aList
[3, 4, 5, 5.5, 7, 9, 11, 13, 15, 17]
>>> aList.index(7)
4
>>> aList.index(100)
Traceback (most recent call last):
File "<pyshell#36>", line 1, in <module>
aList.index(100) 18
使用列表的 count 方法 , 统计指定元素在列表中出现的次
数
>>> aList
[3, 4, 5, 5.5, 7, 9, 11, 13, 15, 7]
>>> aList.count(7)
2
>>> aList.count(11)
1
>>> aList.count(8)
0
19
2.1.3 增加列表元素
1) 使用“ +” 运算符将两个列表合并 , 生成一个新列表
>>> aList = [3, 4, 5]
>>> aList = aList + [7]
>>> aList
[3, 4, 5, 7]
将两个列表中的元素依次复制到新列表 .
由于涉及大量元素的复制 , "+" 操作速度较慢添加大量元素时不
建议使用该方法 .
20
2) 使用列表对象的 append() 方法 , 原地修改列表
在列表尾部添加一个元素 , 速度较快 , 推荐使用 .
“ 原地”指列表对象在内存中的起始地址不变。
>>> aList.append(9)
>>> aList
[3, 4, 5, 7, 9]
21
3) 使 用 列 表 对 象 的 extend() 方 法 , 将 另 一 个 迭 代 对 象
( tuple 、 str 、 list 、 range 等)的所有元素添加至该列
表尾部 .
原地操作 .
>>> a = [5, 2, 4]
>>> id(a)
54728008
>>> a.extend([7, 8, 9])
>>> a
[5, 2, 4, 7, 8, 9]
>>> id(a)
54728008
22
4) 使用列表对象的 insert() 方法将元素添加至指定位置 .
L.insert(index, object) # insert object before index
>>> aList = [3, 4, 5, 7, 9]
>>> aList.insert(3, 6)
>>> aList
[3, 4, 5, 6, 7, 9]
insert() 方法涉及插入位置后所有元素的移动影响处理速度 .
列表删除方法 remove() 和 pop() 弹出非尾部元素时 , 也有类似问
题.
建议 : 除非有必要 , 应尽量避免在列表中间位置插入 / 删除元素 ,
优先使用 append() 和 pop() 在列表尾部增删元素 .
23
5) 使用乘法扩展列表对象 : 列表与整数相乘 , 生成新列表 ,
新列表是原列表的重复 .
>>> x = [[1, 2, 3]]*3
>>> aList = [1, 2, 3]
>>> x
>>> aList = aList*3 [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
>>> x[0][0] = 10
>>> aList
>>> x
[1, 2, 3, 1, 2, 3, 1, 2, 3] [[10, 2, 3], [10, 2, 3], [10, 2, 3]]
不是原地修改 , 也适用于字符串 / 元组 , 并具有相同特点 .
若列表的元素是列表 , 使用“ *” 扩展列表创建多维数组
此时 , 不复制元素的值 , 而是复制值的引用
24
>>> x = [[None] * 2] * 3 # None: 空类型
>>> x
[[None, None], [None, None], [None, None]]
>>> x[0][0] = 5
>>> x # x[0][0], x[1][0], x[2][0] 引用相同值
[[5, None], [5, None], [5, None]]
25
各种增加列表元素方法的比较
列表元素
别名 效果
增加方法
1 + 拼接 新建列表
2 lst.append 附加 原地修改
3 lst.extend 扩展 原地修改
4 lst.insert 插入 原地修改
5 * 复制 新建列表
26
2.1.4 删除列表元素
1. del 命令 : 删除列表指定位置元素 ( 原地操作 ) 或整个列表
>>> a_list = [3, 5, 7, 9, 11]
>>> del a_list[1]
>>> a_list
[3, 7, 9, 11]
27
2. 列表的 pop([index]) 方法
删除并返回指定位置 ( 默认为最后一个 , 即下标为 -1 或者 len of
list -1) 元素 .
若给定索引超出列表范围 , 则抛出异常 .
>>> a_list = list((3, 5, 7, 9, 11)) # 将元组 (3, 5, 7, 9, 11) 转换为列表
>>> a_list.pop() # 默认删除最后一个元素
11 # pop 方法返回值 : 删除的元素
>>> a_list
[3, 5, 7, 9]
>>> a_list.pop(1)
5
>>> a_list
[3, 7, 9] 28
3. 列表的 remove(value) 方法
删除首次出现的指定元素 , 若列表中不存在要删除的元素 , 则抛
出异常 .
>>> a_list = [3, 5, 7, 9, 7, 11]
>>> a_list.remove(7) # 删除第一个 7
>>> a_list
[3, 5, 9, 7, 11]
29
2.1.5 成员资格判断
判断列表中是否存在指定值
• 1) 使用 count() 方法 : 返回大于 0 的数成员存在 , 返回 0 不存
在.
• 2) 使用“ in” 关键字判断某个值是否存在于列表中 ,
返回 True/False.
• 适用于其它可迭代对象 : 元组 , 字典 , range 对象 , 字符串 , 集
合 , …...
• 通常在循环中使用 : 对可迭代对象的元素进行遍历 .
30
>>> aList >>> bList = [[1], [2], [3]]
[3, 4, 5, 5.5, 7, 9, 11, 13, 15, 17] >>> 3 in bList
>>> 3 in aList False
True >>> 3 not in bList
>>> 18 in aList True
False >>> [3] in bList
>>> for v in aList: True
print(v, end = ' ')
3 4 5 5.5 7 9 11 13 15 17
31
2.1.6 切片操作
切片是 Python 序列的重要操作之一 , 适用于列
表 / 元组 / 字符串 /range 对象
32
列表 index 在 [0, len(s)-1]
aList[start : stop : step] 或 [-len(s),
37
功能 2: 使用切片原地修改列表内容 ( 修改 / 删除 / 增加列表元素 )
>>> aList = [3, 5, 7] • 切片下标对应的元素如果为空,
>>> aList[len(aList):] 对列表的切片下标赋值
[] list_var[slice] 时相当于在指定位
>>> aList[len(aList):] = [9,10] # 相当于
置 (stop 所指位置)添加新元
extend([9,10])
素,步长必须为 1
>>> aList
[3, 5, 7, 9,10]
>>> aList[:0] = [-1,1] # 在前面添加元素 • 可以在尾部添加多个元素
>>> aList
[-1, 1, 3, 5, 7, 9, 10] • 可以在前面添加多个元素
>>> aList[3:3] = [500] # 第 3 个位置添加元
素
• 可以在中间添加多个元素
>>> aList
切片操作确实是返回原列表的副本,但是如果把切片作为左值使用的话
[-1, 1, 3, 500, 5, 7, 9, 10]
38
(在赋值号左边出现),会对原列表进行修改。
功能 2: 使用切片原地修改列表内容 ( 修改 / 删除 / 增加列表元素 )
• 切片下标对应的元素如果不为空,给列表的
>>> aList = [3, 5, 7, 9, 10]
切片下标赋值 list_var[slice] 时相当于将下标
>>> aList[:3] = [1, 2, 3,4] # 指定位置的元素替换为赋值语句右边的元素
前面 3 个元素移走后替换,后 • 右边为空列表时相当于删除对应的元素
面的元素相应移位。
>>> aList = list(range(10))
>>> aList >>> aList
[1, 2, 3, 4, 9, 10] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> aList[:3] = [] # 相当于删 >>> aList[: : 2] = [0]*(len(aList)//2)
# 步长不为 1 时要求左右两边的元素个数
除前面 3 个元素 一样
>>> aList >>> aList
[4, 9, 10] [0, 1, 0, 3, 0, 5, 0, 7, 0, 9]
39
功能 3: 使用 del 与切片结合 , 删除多个列表元素
>>> aList = [3, 5, 7, 9, 11]
>>> del aList[: 3] # aList[:3] = []
>>> aList
[9, 11]
40
2.1.7 列表排序
1. 使用列表的 sort 方法进行原地排序——支持多种排序
>>> aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> import random
>>> random.shuffle(aList) # 打乱顺序
>>> aList
[11, 3, 13, 15, 6, 17, 5, 9, 4, 7]
>>> aList.sort() # 默认为升序排列
>>> aList
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17] # aList 发生改变
>>> aList.sort(reverse = True) # 降序排列
>>> aList
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
>>> aList.sort(key = lambda x:len(str(x))) # 按转换成字符串以后的长度升序排序
>>> aList 41
[9, 7, 6, 5, 4, 3, 17, 15, 13, 11]
2. 使用内置函数 sorted(…) 对列表排序并返回新列表
>>> aList
[9, 7, 6, 5, 4, 3, 17, 15, 13, 11]
>>> sorted(aList)
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17] # 输出的是 sorted(aList) 的返回值
>>> aList
[9, 7, 6, 5, 4, 3, 17, 15, 13, 11] # aList 没变
>>> bList = sorted(aList) # 定义新列表把排序结果保存下来
>>> bList
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> bList = sorted(aList, reverse=True)
>>> bList
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
42
3. 列表对象的 reverse 方法——原地逆序
>>> aList = [4, 11, 7, 5, 15, 6, 17, 3, 9, 13]
>>> aList.reverse()
>>> aList
[13, 9, 3, 17, 6, 15, 5, 7, 11, 4]
43
4. 内置函数 reversed(…): 将列表元素逆序并返回新的迭代 (iterator) 对象
>>> aList = [4, 11, 7, 5, 15, 6, 17, 3, 9, 13]
>>> c = reversed(aList)
>>> c
<list_reverseiterator object at 0x01FD0A50>
>>> list(c) # 将迭代对象转换为列表
[13, 9, 3, 17, 6, 15, 5, 7, 11, 4]
>>> list(c)
[] # 无输出内容 , 迭代对象已遍历结束 , 需重新创建迭代对象
>>> c = list(reversed(aList))
>>> c
[13, 9, 3, 17, 6, 15, 5, 7, 11, 4]
44
2.1.8 用于序列操作的常用内置函数
序列大小比较 : 关系运算符 , 序列的 __le__() 及相关方法(不建议使
• 相同类型的对象才能比较,数字类型( bool 、整数、浮点等)的对象之间可以比较
• 用 ).
有序序列的对象可以比较,按顺序比较各个元素的大小,如果前面比较确定了大小关系,则结束。如
果其中某个对象没有对应的元素,则无元素表示其最小
• 字符之间的比较按照 Unicode 顺序比较,即 ord(char) 之间的比较。 空格… 0…9 …A…Z… a…z …
>>> [1,2,3] < [1,2,4]
True
>>> 'ABC' < 'C' < 'Pascal' < 'Python' >>> a = [1, 2]
True >>> b = [1, 2, 3]
>>> (1,2,3,4) < (1,2,4) >>> a.__le__(b)
True True
>>> (1,2) < (1,2,-1) >>> a.__gt__(b)
True False
>>> (1,2,3) == (1.0,2.0,3.0) >>> a > b
True False
>>> (1,2,('aa','ab')) < (1,2,('abc','a'),4)
>>> a < b
True
>>> 'a' > 'A' True
45
True
len( 列表 )
max( 列表 ), min( 列
表)
• 返回列表中的最大或最小元素 , 还适用于元组 /range.
sum( 列表 )
• 对数值型列表的元素进行求和运算 , 对非数值型列表运算出错 , 同
样适用于元组 /range.
46
for 循环
标识语句块 ( 缩 index = 0
for x in seq :
进 ) 即将开始
缩进 循环体
index < len(c) False
x: 自定义变量 , seq: 序列对象
e.g. for i in c: True
print(i, end = ' ') i = c[index]
index: 内部隐含变量 ; 灰
print(i, end = ' ')
色框 : 内部隐含操作
每次比较时 , 重新计算 index = index +1
len(c)
47
2.1.9 列表推导式——轻量级循环
利用其它列表创建新列表的一种方法 .
[ 表达式 for 变量 in 列表 (if 条件 )] # "if 条件 " 可选
[expr for value in seq (if condition)] # 列表元素 : expr 的运算结果
此处 if 主要起条件判断作用, seq 数据中只有满足 if 条件的先被
留下,最后才统一生成为一个数据列表
相当于
48
过滤不符合条件的元素—— if 子句
>>> aList = [-1, -4, 6, 7.5, -2.3, 9, -11]
>>> [i for i in aList if i > 0] # 过滤掉列表中的非正数
[6, 7.5, 9]
使用列表推导式实现嵌套列表的平铺—— for 子句嵌套
49
嵌套循环
vec=[[1,2,3],[4,5,6],[7,8,9]]
v=[]
for elem in vec:
for num in elem:
vec v.append(num)
num 1 2 3 4 5 6 7 8 9
50
在列表推导式中使用多个循环 , 可实现多序列元素的任意
组合 , 还可结合条件语句过滤特定元素 .
51
列表推导式中可使用函数或复杂表达式
复杂表达式格式如下:
[exp1 if condition else exp2 for x in seq(if condition) ]
(其中的 if else 必须一起出现)
52
2.2 元组
2.2.1 元组的创建与删除
2.2.2 元组与列表的区别
2.2.3 序列解包
2.2.4 生成器推导式
53
2.2.0 元组
和列表类似 , 但属于不可变序列 .
一旦创建 , 用任何方法都不能修改其元素 .
54
>>> a_tuple = ('a', 'b', 'mpilgrim', 'z', 注意 : 若创建只有一个元素的
'example') 元组 , 需在元素后加上逗号 .
>>> a_tuple >>> a_tuple = ('a', )
('a', 'b', 'mpilgrim', 'z', 'example') >>> a_tuple
>>> x = () # 空元组 ('a',)
>>> x >>> a = 'a',
() >>> a
>>> x = 1,2,3 # 不引起歧义时 , 括号可 ('a',)
省 >>> a = ('a') # 解释为表达式
>>> x >>> a
(1,2,3) 'a'
55
2.2.1 元组的创建与删除
tuple 函数——将其它序列转换为元组并返回
>>> print(tuple('abcdefg')) # 将字符串转换为元组
('a', 'b', 'c', 'd', 'e', 'f', 'g')
>>> aList = [-1, -4, 6, 7.5, -2.3, 9, -11]
>>> tuple(aList) # 将列表转换为元组
(-1, -4, 6, 7.5, -2.3, 9, -11)
>>> s = tuple() # 空元组
>>> s
()
使用 del 删除整个元组 , 不能删除元组元素
56
元组访问 ( 补 )
与 list/str 一样 , 可以访问某个元素 , 但不能赋值
1) 下标访问某个元素
>>> x = tuple([x**2 for x in range(12)]) # 把列表推导式生成的列表转换为元组
>>> x
(0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121)
>>> x[5], x[-2]
(25, 100)
2) 切片访问多个元素
>>> x[-1: : -1]
(121, 100, 81, 64, 49, 36, 25, 16, 9, 4, 1, 0)
>>> x[0: 10: 2]
(0, 4, 16, 36, 64)
57
tuple 的元素可以是可变对象
tuple 的元素不可变 , 但是元素指向的对象可变
>>> x = (1, 2, [4, 5])
>>> x[2] = [5, 5]
TypeError: 'tuple' object does not support item assignment
>>> x[2][0] = 5
>>> x
(1, 2, [5, 5])
>>> x[2].append(8)
>>> x
(1, 2, [5, 5, 8]) 58
除了索引 ( 下标 ) 和切片访问外 , 还支持序列的其它基本
操作
连接和重复 e.g. (1, 2) + (‘a’, ‘b’) (1, 2) * 2 # 生成新的元组
成员关系操作 :
in/not in e.g. 1 in (1, 2) '1' not in (1, 2)
count(x): x 出现的次数 e.g. (1, 2).count(1)
index(value, [start, [stop]]) value 在指定范围第一次出现的下
标 , 找不到时抛出异常 ValueError. e.g. (1, 2).index(1)
比较运算 : < <= == != >= >
59
内置函数对元组的操作
• sorted(iterable): 排序后返回新元组
• len(iterable), max(iterable), min(iterable): 长度 , 最大值 ,
最小值
• sum(iterable): 数值元素的和
• enumerate(iterable): 返回枚举对象 ( 包含下标和值的元
组)
• zip(iter1, iter2…): 返回 zip 对象 ( 多个可迭代对象中对应位
置元素组成的元组 )
60
zip( 列表 1, 列表 2, …)
将多个列表对应位置元素组合为元组 , 返回包含这些元组的 zip 对
象.
Zip 对象可用 list() 函数转换为列表 .
>>> aList = [1, 2, 3]
>>> bList = [4, 5, 6]
>>> cList = zip(aList, bList)
>>> cList
<zip object at 0x0000000003728908>
>>> list(cList)
[(1, 4), (2, 5), (3, 6)] # 列表的元素是元组
>>> list(cList)
[]
61
enumerate( 列表 )
枚举列表元素 , 返回枚举对象 : 每个元素为包含下标和值的元组 .
枚举对象可用 list() 函数转换为列表 .
该函数对元组 / 字符串 /zip 对象同样有效 .
>>> dList = [5, 6, 7] >>> dList = [5, 6, 7]
>>> for item in enumerate(dList): >>> d=enumerate(dList)
>>> d
print(item)
<enumerate object at
(0, 5) 0x0000000002D77B80>
(1, 6) >>> list(d)
(2, 7) [(0, 5), (1, 6), (2, 7)]
>>> list(d)
[]
62
2.2.2 元组 vs 列表
元组中的元素一旦定义就不允许更改
• 没有 append()/extend()/insert() 等方法 , 无法向元组添加元素 ;
• 没有 remove()/pop() 方法 , 无法对元组元素进行 del 操作 .
63
元组的元素不可变 , 但元素所指向的对象可变 .
>>> x = ([1, 2], 3)
>>> x[0][0] = 5
错误说明 :
>>> x
列表的 + 运算会创建一个新的列表,
([5, 2], 3)
对 x[0] 的赋值就是尝试修改元组元素
>>>x[0].append(8)
>>>x 的值(所指对象),所以这是不允许
([5, 2, 8], 3) 的,会报错。
>>>x[0] = x[0] + [10]
TypeError: 'tuple' object does not support item assignment
64
元组的优点
元组的速度比列表快 : 若定义了一系列常量值 ,
仅需对它们进行遍历 ( 读操作 ) 使用元组较列
表更佳。
元组对不允许改变的数据进行“写保护” , 使代
码更加安全。
元组可用作字典键 ; 而列表不可 , 因为可变。
65
2.2.3 序列解包 (sequence unpacking)
对多个对象引用 ( 变量等 ) 同时赋值 LHS = RHS
LHS 可以是变量名 , 或是通过下标 / 切片描述的多个 list 元素
LHS 可通过圆括号、方括号组织 , 通过逗号分割
RHS 可以是任何可迭代对象 , 包括 tuple/list/dict/range/str 等逐个
取该序列的元素赋予左边对应位置的对象
>>> a,b,c = [1,2,3]
>>> (x, y, z) = (False, 3.5, 'exp') >>> a,b,c
>>>x, y, z = (False, 3.5, 'exp') (1, 2, 3)
>>>a, b, c = 'abc'
>>> x, y, z >>> a, b, c
(False, 3.5, 'exp') ('a', 'b', 'c') 66
除了带星号的对象引用 (*seq) 外 , 要求 RHS 与 LHS 有相同
数量的元素 .
带星号的对象最多出现一次 , 该对象前后的变量一一对应赋值后 ,
剩余的值转换为 list 然后赋予该引用 .
>>> a, *b, c = range(1, 7)
>>> a, b, c
(1, [2, 3, 4, 5], 6)
67
序列解包中 , LHS 可以是列表元素或者切片
>>> list1 = list(range(12)) # list1 = [0,1,2,3,4,5,6,7,8,9,10,11]
>>> x, y, list1[-1], list1[0: 5] = 3, 4, 0, range(-5, 0)
>>> list1
[-5, -4, -3, -2, -1, 5, 6, 7, 8, 9, 10, 0]
序列解包可嵌套
>>> a, [b, (c, d)] = 1, ['hello', ('Steve', 'Lee')]
>>> a, b, c, d
(1, 'hello', 'Steve', 'Lee')
68
序列解包例子
>>> keys=['a','b','c','d'] >>> aList = [1,2,3]
>>> values=[1,2,3,4] >>> bList = [4,5,6]
>>>for k,v in zip(keys,values): >>> cList = [7,8,9]
print(k,v) >>> dList = zip(aList, bList, cList)
>>> for index, value in enumerate(dList):
a1 print(index, ':', value)
b2 0 : (1, 4, 7)
c3 1 : (2, 5, 8)
d4 2 : (3, 6, 9)
69
内置函数 eval(): 将字符串当成有效的表达式来求值并返回计算结
果。
>>> x,y,z=eval('10+2,20,"a" ')
>>> x,y,z
(12, 20, 'a')
eval() 可以把 list,tuple,dict 和 string 相互转化
结果是一个生成器对象 , 可转换为列表 / 元
组
• 可使用生成器对象的 __next__() 方法进行遍历 , 也可采用内置函数
next(obj)
• 遍历时 , 元素指针往前移动 . 遍历完最后一个元素后 , 下一个元素
将抛出异常 StopIteration.
生成器对象只在需要时生成新元素,与列表推导式相比,更有效率,空间占用少71
>>> g=((i+2)**2 for i in range(10))
>>> g=((i+2)**2 for i in range(3))
>>> next(g) # g.__next__()
>>> g
4
<generator object <genexpr> at
>>> next(g)
0x02B15C60>
9
>>>tuple(g)
>>> next(g)
(4, 9, 16,)
16
>>> tuple(g)
>>> next(g)
()
Traceback (most recent call last):
….
StopIteration
72
[ 例 ] 生成器推导式
毕达哥拉斯三元组 : 存在 {x, y, z}, 0<x<y<z, 使得 x^2+y^2=z^2. 求
前 10 个毕达哥拉斯三元组 .
# 方法 1 列表推导式
pyt = [(x,y,z) for z in range(100) for y in range(1,z) for x in range(1,y)
if x*x + y*y == z*z ]
firstN_pyt = pyt[:10]
print(firstN_pyt)
# 方法 2 生成器推导式
pyt = ((x,y,z) for z in range(1000) for y in range(1,z) for x in
range(1,y) if x*x + y*y == z*z )
firstN_pyt = [next(pyt) for x in range(10) ]
print(firstN_pyt ) 75
2.3 字典
如何保存一个电话号码簿 ?
用列表
phonebook = [('Alice', '2341'), ('Beth', '9102'), ('Cecil', '0142')]
需要获取 Beth 的号码时 : phonebook[1][1]. 缺点 : 不直观
我们希望是 : phonebook['Beth']
通过关键词而不是编号来引用值
76
主要内容
2.3.1 字典的创建与删除
2.3.2 字典元素的读取
2.3.3 字典元素的添加与修改
2.3.4 字典应用案例
2.3.5 有序字典
77
字典 (dict)
字典是包含键 - 值对的无序的可变序列 , 也称为映射 (mapping) 类型
字典中的每个元素包含两部分 : 键和值
值 (values) 可以是任何对象
• 每个 key 对应一个值 , 可通过 key 查询到其对应的值 .
78
[ 例 ] Python 环境中 , 许多内置函数和变量使用了
dict
79
2.3.1 字典的创建与删除
1) 通过 dict literal 创建 dict 对象
大括号界定 , 元素用 key:value 表示 , 元素间用逗号分隔
{key1: value1 , key2: value2, … , keyN: valueN }
d1 = { 1: 'food', 2: 'drink', 3: 'fruit' }
d2 = {} # 空字典
d3 = {'name': 'Steve', 'age': 25, 'gender': 'male',
'address': {'city': 'shanghai', 'zipcode': '200433'}, # 嵌套的字
典
1: 'note1', 2: 'note2',
'1': 'xx1', '2': 'xx2' }
80
2) 通过 dict() 函数创建 dict 对象
dict(): 创建空字典
dict(iterable): 新字典的元素来自于 iterable, 每个元素 ( 可以为
list 、 tuple 、 zip 对象、 enumerate 等 ) 必须包括两个子元素
dict(mapping): 从字典对象 mapping 创建一个新字典对象
dict(**kwargs): 从关键字参数 kwargs 创建一个新字典对象
关键字参数 keyvar=value 对应的字典元素 : 'keyvar': value
phonebook = dict([('Alice', '2341'), ('Beth', '9102'), ('Cecil', '0142')])
phonebook = dict(zip(['Alice', 'Beth', 'Cecil'], ['2341', '9102',
'0142']) )
phonebook = dict({'Alice': '2341', 'Beth': '9102', 'Cecil': '0142'})
phonebook = dict(Alice = '2341', Beth = '9102', Cecil = '0142')
81
3) 通过 dict 类的方法创建新字典
dict.fromkeys(seq[, value])
每个元素的 key 来自于序列对象 seq, 值设置为 value, 缺省为
None.
>>> dict1 = dict.fromkeys(['name', 'age', 'gender'])
>>>dict1
{'age': None, 'name': None, 'gender': None}
>>> dict2 = dict.fromkeys(range(5), 10)
>>> dict2
{0: 10, 1: 10, 2: 10, 3: 10, 4: 10}
使用 del 删除整个字典 : del dict2
len(d): 返回字典中元素个数 82
序列解包对字典同样有效
>>> b, c, d = {'a': 1, 'b': 2, 'c': 3} # 保存键 , 丢弃值
>>> b, c, d
('a', 'b', 'c')
83
字典支持的方法 说明
d[key] 返回 key 对应的 value, key 不存在抛出 KeyError
d.get(key[, default]) 返回 key 对应的 value, key 不存在时返回 default, 缺省为 None
d.keys() 返回可迭代对象 , 元素为字典中所有的 key
d.values() 返回可迭代对象 , 元素为字典中所有的 value
d.items() 返回可迭代对象 , 元素为 (key, value) 元组
key in d
key not in d 判断字典 d 中有 / 没有键为 key, 返回 True/False, 相当于 key in d.keys()
d[key] = value 设置字典中键为 key 的元素的值为 value, 若不存在 , 则添加 key: value 元素
setdefault(key[, default]) 若 key 不在字典里 , 则插入新元素 key:default( 缺省 None); 若在 , 不更新 , 返
回 d[key]
update(other) 用另一字典或元素 (key:value) 更新字典 , 返回 None
del d[key] 删除元素 , 若 key 不存在 , 抛出 KeyError
popitem() 移走并返回某一个 (key:value)
pop(key) 若 key 存在 , 删除对应元素并返回值 ; 否则抛出 KeyError
pop(key, value) 若 key 存在 , 删除对应元素并返回值 ; 否则返回 value
clear() 清除所有元素
2.3.2 字典元素的读取 : 下标
以键作为下标访问字典元素 , 若键不存在则抛出异常 KeyError
>>> aDict = {'name': 'Dong', 'gender': 'male', 'age': 37}
>>> aDict['name']
'Dong'
>>> aDict['address ']
Traceback (most recent call last):
File "<pyshell#53>", line 1, in <module>
aDict['address']
KeyError: 'address'
85
d.get(key[, default])
返回 key 对应的 value, key 不存在时返回 default, 缺省为 None
aDict = {'name': 'Dong', 'gender': 'male', 'age': 37}
>>> print(aDict.get('address'))
None
>>> print(aDict.get('address', 'SDIBT'))
SDIBT
>>> aDict[‘score’] = aDict.get(‘score’, []) # 增加一个新元素
# 也可以直接赋值 aDict[‘score’] =[]
>>> aDict['score'].append(98)
>>> aDict['score'].append(97)
>>> aDict
{'age': 37, 'score': [98, 97], 'name': 'Dong', gender': 'male'} 86
d.keys() 返回可迭代对象 , 元素为字典中所有的 key
d.values( 返回可迭代对象 , 元素为字典中所有的 value
)
d.items() 返回可迭代对象 , 元素为包括了 (key, value) 的元组
iter(d) 等价于 iter(d.keys()), 即 d 的迭代器是针对所有 key
d = {'name':
的'Dong', 'gender': 'male', 'age': 37}
for item in d.items(): for key, value in d.items(): for key in d: for key in d.keys():
print(item) print(key, value) print(key) print(key)
('age', 37) age 37 age
('gender', 'male') gender male gender
('name', 'Dong') name Dong name
for value in d.values(): >>> list(d.items())
print(value) [('age', 37), ('gender', 'male'), ('name', 'Dong')]
37 >>> list(d)
male ['age', 'gender', 'name']
Dong 87
2.3.3 字典元素的添加与修改
d[key] = value
若键存在 , 修改该键的值 ; 若不存在 , 则添加一个键值对 .
d = {'name': 'Dong', 'gender': 'male', 'age': 37}
>>> d['age'] = 38 # 修改
>>> d
{'age': 38, 'name': 'Dong', 'gender': 'male'}
>>> d['address'] = 'SDIBT' # 添加
>>> d
{'age':38, 'address':'SDIBT', 'name': 'Dong', 'gender': 'male'}
88
d.update(another)
用另一个字典 another 的键值对修改 / 添加到当前字典对象 d
>>> d = {'age': 37, 'score': [98, 97], 'name': 'Dong', 'gender': 'male'}
>>> d.update({'age': 38, 'city': 'shanghai'})
>>> d
{'age': 38, 'score': [98, 97], 'name': 'Dong', 'city': 'shanghai', 'gender':
'male'}
89
del d[key] 删除元素 , 若 key 不存在 , 抛出 KeyError
popitem() 返回并删除字典中的最后一对键和值 (key, value)
pop(key) 若 key 存在 , 删除对应元素并返回值 , 否则抛出 KeyError
pop(key, value) 若 key 存在 , 删除对应元素并返回值 , 否则返回 value
clear() 清除所有元素
>>> d = { 'age': 38, 'score': [98, 97], 'name': 'Dong', 'city': 'shanghai', 'gender': 'male'}
>>> d.popitem()
('gender', 'male')
>>> d.pop('score', [])
[98, 97]
>>> d.pop('score', [])
[]
90
字典推导式
91
2.3.4 字典应用案例
[ 例 ] 生成包含 1000 个随机字符的字符串 , 统计每个字符的
出现次数 .
方法一 : 以 " 字符 : 次数 " 键值对的形式保存到字典
中.
92
import string
import random
charset = string.ascii_letters + string.digits + string.punctuation
print('\n 可使用的字符集 : \n', charset)
charList = [random.choice(charset) for i in range(1000)]
randString = ''.join(charList) # 由字符列表构成字符串
freq = dict() # 定义空字典
for ch in randString:
freq[ch] = freq.get(ch, 0) + 1
# 若 ch 不在字典中 , 添加键值对 (ch:1); 否则 , 将 ch 对应的值增加 1
print('\n 随机产生的字符串为 : \n', randString)
print('\n 方法一的统计结果为 : \n', freq)
93
方法二 : 使用 collections 模块的 defaultdict 类 ( 提供缺省值的 dict) 实
现该功能 . (可选)
import string
import random
charset = string.ascii_letters + string.digits + string.punctuation
print('\n 可使用的字符集 : \n', charset)
charList = [random.choice(charset) for i in range(1000)]
randString = ''.join(charList) # 由字符列表构成字符串
96
2.3.5 有序字典 ( 可选 )
Python 的内置字典是无序的
collections.OrderedDict: 可记住元素插入顺序的字典
>>> x = dict() # 无序字典 >>> import collections
>>> x['a'] = 3 >>> x = collections.OrderedDict() # 有序字典
>>> x['b'] = 5 >>> x['a'] = 3
>>> x['c'] = 8 >>> x['b'] = 5
>>> x >>> x['c'] = 8
{'b': 5, 'c': 8, 'a': 3} >>> x
OrderedDict([('a', 3), ('b', 5), ('c', 8)])
97
2.4 集合
2.4.1 集合的创建与删除
2.4.2 集合操作
98
2.4.1 集合 (set) 的创建与删除
无序可变 , 使用一对大括号界定 , 元素间以逗号分隔 .
a = {} 产生空字典对象而不是空集合
99
>>> a = {3, 7, 5, 5} >>> a = set(range(8, 14))
>>> a >>> a
{3, 5, 7} # 自动去重 {8, 9, 10, 11, 12, 13}
>>> a = {3, [1, 2]} >>> b= set([0, 1, 2, 3, 0, 1, 2, 3, 7, 8])
TypeError: unhashable type: 'list' >>> b
{0, 1, 2, 3, 7, 8} # 自动去重
>>> c = set() # 空集合
>>> c
set()
• 使用 del 删除整个集合
100
2.4.2 集合的运算 : 比较运算和内置函数
比较
== != 判断两个集合是否相等
< > 判断前一集合是否为后者的真子集 / 真超集
<= >= 判断前一集合是否为后者的子集和超集
元素是否存在 :
x in s 或者 x not in s: 判断元素 x 是否在集合 s 中
len(s): 集合的元素个数
max(s)/min(s)/sum(s): 集合中元素的最大值、最小值、和
101
方法 说明 例子
s1 | s2 | … 并集 , s1 ∪ s2 ∪ …
s1.union(s2, …) {1, 2, 3} | {2, 4} ⇨ { 1, 2, 3, 4}
在任一个集合出现
s1 & s2 & … 交集 , s1 ∩ s2 ∩…
s1.intersection(s2, …) {1, 2, 3} & {2, 4} ⇨ {2}
在所有集合出现
s1 – s2 差集 , s1 – s2
s1.difference(s2) {1, 2, 3} - {2, 4} ⇨ { 1, 3}
在 s1 但不在 s2
s1 ^ s2 对称差集 , s1 ⊕ s2
s1.symmetric_difference(s2 属于其中一个但不属于另一个 {1, 2, 3} ^ {2, 4} ⇨ { 1, 3, 4}
) = (s1 ∪ s2) -s1 ∩ s2
{1, 2, 3} .isdisjoint({2, 4})
s1.isdisjoint(s2) 没有共同元素为 True ⇨ False
s1.issubset(s2)
s1 <= s2 s1 是否为 s2 的子集 {1, 2} <= {1, 2, 4} ⇨ True
s1.issuperset(s2)
s1>= s2 s1 是否为 s2 的超集 {1, 2, 4} >= {1, 2} ⇨ True
集合元素的更改 s1 = {1, 2, 3}, s2 = {2, 3,
4}
方法 说明 例子
s.add(x) 将 x 添加到集合 s s1.add('a') ⇨ s1 = {1, 2, 3, 'a'}
s1.update(s2) 并集 s1 =s1 | s2 s1.update(s2)⇨s1 = {1, 2, 3,
4}
s1.intersection_up 交集 s1 = s1 & s2 s1.intersection_update(s2)
date(s2) ⇨ s1 = {2, 3}
s1.difference_upd 差集 s1 = s1 – s2 s1.difference_update(s2)
ate(s2) ⇨ s1 = {1}
s1.symmetric_diff 对称差集 s1 = s1 ⊕ s2 s1.symmetric_difference_upda
erence_update(s2 te(s2) ⇨ s1 = {1, 4}
)
s.remove(x) 从集合 s 中移除 x, 不存在抛出异常 s1.remove(1) ⇨ s1 = {2, 3}
KeyError
s.discard(x) 从集合 s 中移除 x s1.discard(1) ⇨ s1 = {2, 3}
s.pop() 从集合 s 随机移除一个元素并返回 , 空时 s1.pop() # return 1, s1 = {2,
抛出 KeyError 3}
103
s.clear() 清空集合 s s1.clear() ⇨ s1 = set()
集合的应用 : 去除 list 重复元素
import random
listRandom = [random.randint(1,10) for i in range(20)]
print(listRandom)
# 方法一: # 方法二:
noRepeat = [] newSet = set(listRandom)
for i in listRandom : noRepeat = list(newSet)
if i not in noRepeat: print(noRepeat)
noRepeat.append(i) # 方法三:
print(noRepeat) newDict = dict.fromkeys(listRandom)
noRepeat = list(newDict.keys())
print(noRepeat)
105
不可变集合 frozenset
set 的元素可变
frozenset 为不可变集合对象,只能通过 forzenset() 函数来创建,
与 set() 函数类似
除了集合元素的更改类的操作不支持外, set 的其他操作都可应用
于 frozenset 。
>>> a = frozenset(range(10))
>>> a
frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
106
2.5 再谈内置方法 sorted()
列表对象提供了 sort() 方法支持原地排序,
内置函数 sorted() 返回新的列表,可对元组、列表、字典等进行排
序,借助于其 key 参数可以实现自定义的的排序。
sorted 语法: sorted(iterable, key=None, reverse=False) , Python3
值,以确定结果的顺序。
reverse -- 排序规则, reverse = True 降序 , reverse = False 升序
(默认)。
107
>>> persons = [{'name':'Dong', 'age':37}, {'name':'Zhang', 'age':40},
{'name':'Li', 'age':50}, {'name':'Dong', 'age':43}]
>>> print(persons)
[{'name': 'Dong', 'age': 37}, {'name': 'Zhang', 'age': 40}, {'name': 'Li',
'age': 50}, {'name': 'Dong', 'age': 43}]
# 使用 key 来指定排序依据,先按姓名升序排序,姓名相同的按年龄降序排序
• 定义一个函数对象 sort_by_name_age ,该函数调用时传递的参数为要排序的元
素(这里是字典对象),返回两元元组,第一个元素为姓名,第二个元素为年
龄的负值
• 元组的比较:第一个元素比较大小,如果相同的情况下比较第二个元素,如此
继续…
def sort_by_name_age(item):
return item['name'],-item['age']
print(sorted(persons, key=sort_by_name_age))
[{'name': 'Dong', 'age': 43}, {'name':
'Dong', 'age': 37}, {'name': 'Li', 'age':
50}, {'name': 'Zhang', 'age': 40}] 108
• 采用 lambda 表达式定义一个匿名函数对象,该函数参数为 item ,
而冒号后面的为要返回的表达式 , 即 (item['name'], -
item['age'])
>>> print(sorted(persons, key=lambda item:(item['name'], -
item['age'])))
109
2.5 再谈内置方法 sorted() (选
讲)
operator 模块的 itemgetter 函数: itemgetter(item)
itemgetter 函数用于获取对象的哪些维的数据。
operator.itemgetter 函数获取的不是值,而是定义了一个函数,通过该函数作用
到对象上才能获取值。
a = [1,2,3]
>>> b=operator.itemgetter(1) // 定义函数 b ,获取对象的第 1 个域的
值
>>> b(a)
2
>>> b=operator.itemgetter(1,0) // 定义函数 b ,获取对象的第 1 个域和第
0 个的值
>>> b(a)
(2, 1)
110
>>> phonebook = {'Linda':'7750', 'Bob':'9345', 'Carol':'5834'}
>>> from operator import itemgetter
>>> sorted(phonebook.items(), key=itemgetter(1))
# 按字典中元素的值进行排序
[('Carol', '5834'), ('Linda', '7750'), ('Bob', '9345')]
>>> sorted(phonebook.items(), key=itemgetter(0))
# 按字典中元素的键进行排序
[('Bob', '9345'), ('Carol', '5834'), ('Linda', '7750')]
111
>>> gameresult = [['Bob', 95.0, 'A'], ['Alan', 86.0, 'C'], ['Mandy', 83.5, 'A'], ['Rob', 89.3, 'E']]
[['Bob', 95.0, 'A'], ['Mandy', 83.5, 'A'], ['Alan', 86.0, 'C'], ['Rob', 89.3, 'E']]
112
>>> gameresult = [{'name':'Bob', 'wins':10, 'losses':3, 'rating':75.0},
{'name':'David', 'wins':3, 'losses':5, 'rating':57.0},
{'name':'Carol', 'wins':4, 'losses':5, 'rating':57.0},
{'name':'Patty', 'wins':9, 'losses':3, 'rating':72.8}]
113