Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 111

第 2 章 Python 序列

主要内容
 列表
 元组
 字典
 集合
 再谈内置方法

2
2.0 序列
一系列相关的对象 .

序列成员称为“元素” .

程序设计中常用的数据存储方式
• 几乎每种程序设计语言都提供了列表数据结构 , 如 : C 和 Basic 的一维、多维数组 .

Python 提供的序列类型在所有程序设计语言中最丰富 , 最灵活 , 功能最强


大.

3
 常用的序列结构 : 列表 , 元组 , 字典 *, 字符串 , 集合 *,
range
可变 不可变
有序 列表 元组 **, 字符串
字典 , 集
无序

 有序序列 ( 列表 / 元组 / 字符串 ) 支持双向索引 :


正向索引 : 第一个元素的下标为 0, 第二个元素的下标为 1, ……;
反向索引 : 最后一个元素的下标为 -1, 倒数第二个元素的下标为
* 在有些表述中 , 字典和集合不属于序列 . -2,
…… ** 若元组的元素可变(所引用对象) , 则元组可变 . 4
2.1 列表
 Python 内置的可变序列 , 若干元素的有序集合 .
 所有元素放在一对“ []” 中 , 元素之间以“ ,” 分隔
 各元素的类型可相同 / 不同 : 整数 / 实数 / 字符串等基本类型 , 列
表 / 元组 / 字典 / 集合 , 其它自定义类型的对象。
例如: [10, 20, 30, 40]
['crunchy frog', 'ram bladder', 'lark vomit']
['spam', 2.0, 5, [10, 20]]
[['file1', 200, 7], ['file2', 260, 9]]
5
 列表元素的访问
 列表是有序序列通过下标访问列表中某个元素 .
 正 向 下 标 : 0, 1, …… , len(seq)-1; 反 向 下 标 : -1, -2, …… , -
len(seq) ;
 下标越界程序报错 .
>>> aList = [10, 20, 30, 40] # 二维数组的访问 :
>>> aList[0] >>> aList = [[1, 2, 3], [4, 5, 6]]
10 >>> aList[0]
>>> aList[4]
Traceback (most recent call last): [1, 2, 3]
File "<pyshell#48>", line 1, in >>> aList[0][0]
<module> 1
aList[4] >>> aList[1][2]
IndexError: list index out of range 6
6
>>> a=100
 列表在内存中的存放 >>>str= "123”
>>> li=[100, "123"]
li a str >>> id(li)
47842560
Li[0] Li[1] 100 '123' >>> id(li[0])
8791137641216
>>> id(a)
8791137641216

 列表元素 vs 元素值 : 列表元素为元素值的引用(或内存地址) ,


而非元素值本身 .
 增加 / 删除列表元素时 , 列表自动扩展 / 收缩 , 保证元素在内存中
连续存放 , 但元素值并非连续存放 .
 列表的修改
 修改变量值时 , 并非直接修改变量的值 , 而是使变量指向新的值
同样适用于列表 .
>>> a = [1, 2, 3]
>>> id(a)
20230752
>>> a = [1, 2] # a 指向新的列表
>>> id(a)
20338208

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 对象

• 语法格式 : list[start:stop:step] e.g. lst = [1, 2, 3, 4, 5]


• start: 切片的开始位置 ( 默认为 0)
• lst[::], lst[:] 二者等价
stop: 切片的截止 ( 但不包含 ) 位置 ( 默认为列表长度 )
• step: 切片的步长 ( 默认为 1), 若省略则第二个冒号亦可省
略.
• 返回值 : 列表元素的拷贝 .

32
列表 index 在 [0, len(s)-1]
aList[start : stop : step] 或 [-len(s),

 当 step 为正数且 start 、 stop 符号相同时,


 若 start < stop ,则切片为顺序;
 若 start stop ,则切片为空。
 当 step 为负数且 start 、 stop 符号相同时,
 若 start stop ,则切片为空;
 若 start > stop ,则切片为倒序。
 当 start 、 stop 符号不同且未超出索引范围时,可以
通过“负数值 +len(aList)” 的方法,使得负数变成正数。
 对于超出索引范围的 stop 值,
 stop > len(aList) 时,可用 len(aList) 代替 stop ;
 stop < -len(aList) 时,可用 -len(aList)-1 代替 stop 。 33
aList[start : stop : step] 红点表示下标的有效取值( star , step )同
1. start stop , step 0 号
start step stop
[ )
2. start stop , step 0 ( 列表为空 )
stop start
( ]
3. start stop , step 0
stop - step start
( ]
4. start stop , step 0 ( 列表为空 )
start stop
[ ) 34
例子: aList[ start : stop ] step 默认为 1

 如果 start 与 stop 符号相同且 startstop ,则 aList[start : stop]


返回一个空表:
a[-1 : -4] 、 a[4 : 4] 、 a[4 : 1] 均返回空表。
 如果 start 或 stop 是负数(绝对值),则用 len(aList)+start 或
stop 替换下标:
a[1 : -3] 与 a[1 : -3+len(a)] 一样,
b[-4 : -2] 与 b[-4+len(b) : -2+len(b)] 一样。
 如果 stop>len(List) ,则用 len(aList) 代替 stop 。
35
 切片的功能
 功能 1: 截取列表中的任何部分 , 得到一个新列表 .
>>> aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17] >>> aList[3: 6]
>>> aList[: : ] [6, 7, 9]
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17] >>> aList[3: 6: 1]
>>> aList[: : -1] # 反向切片 [6, 7, 9]
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3] >>> aList[0: 100: 1]
>>> aList[: : 2]
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
[3, 5, 7, 11, 15]
>>> aList[1: : 2] >>> a[100: ]
[4, 6, 9, 13, 17] []
>>> aList[3: : ]  与使用下标访问列表元素的方法不同 , 切片操
[6, 7, 9, 11, 13, 15, 17]
作不会因下标越界而抛出异常 : 只是在列表尾
部截断或返回空列表 , 代码具有更强的健壮
性.
 切片返回的是列表元素的浅拷贝
>>> aList = [3, 5, 7] 什么是浅拷贝?
>>> bList = aList[::] # 浅复制
>>> aList == bList
仅仅 copy 了原有列表对象中各个元素的
True 引用,即新列表和原列表相同位置的元
>>> aList is bList 素都指向同一个对象。
False
>>> id(aList) == id(bList) 与前面 list() 的描述类似
False
>>> bList[1] = 8 list_a = [1,2,[4,5]]
>>> bList list_b = list_a[:]
[3, 8, 7]
>>> aList list_a[2][0] = 5
[3, 5, 7]
print(list_b) #output [1,2,[5,5]]

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( 列表 )

• 返回列表中的元素个数 , 还适用于元组 / 字典 / 字符串 /range, ...

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)

elem [1,2,3] [4,5,6] [7,8,9]

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 操作 .

tuple( ) 函数可接受一个列表参数 , 返回一个包含同样元素


的元组 ; 而 list( ) 函数可接受一个元组参数并返回一个列
表.
• 从效果上看 , tuple( ) 冻结列表 , 而 list( ) 融化元组 .

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 相互转化

>>> a="[1,2,3,4]" >>> a=list(eval('10+2,20,"a" '))


>>> b=eval(a) >>> a
>>> b [12, 20, 'a']
[1, 2, 3, 4] 70
2.2.4 生成器推导式
与列表推导式相似 , 使用 '()' 而不是 '[]'.

结果是一个生成器对象 , 可转换为列表 / 元

• 可使用生成器对象的 __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) 类型

字典中的每个元素包含两部分 : 键和值

键 (keys) 是不可变对象 ( 数据 ) , 且不允许重复


• 可以是整数 , 实数 , 复数 , 字符串 , 元组 , ...
• 不同元素的 key 类型可以不同 .
• 无序 : 不是按照 key 的大小顺序排列 , 而是按照 key 的 hash 值排列 .

值 (values) 可以是任何对象
• 每个 key 对应一个值 , 可通过 key 查询到其对应的值 .

78
[ 例 ] Python 环境中 , 许多内置函数和变量使用了
dict

sys.modules: 返回 globals(): 返回包含 locals(): 返回包含


当前已加载的模块 当前作用域内所有 当前作用域内所有
名与模块对象的映 全局变量和值的字 局部变量和值的字
射. 典. 典.

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) # 由字符列表构成字符串

from collections import defaultdict


freq = defaultdict(int) # 字典 freq 每个键的默认值为整型值 0
for ch in randString:
freq[ch] += 1
print('\n 方法二的统计结果为 : \n', freq)
94
 方法三 : 使用 collections 模块的 Counter 类 , 自动统计次数并按次数
降序排列 . 还能满足其它需要 , 如 : 查找出现次数最多的元素 . (可
选)
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) # 由字符列表构成字符串

from collections import Counter


freq = Counter(randString)
print('\n 方法三的统计结果为 : \n', freq) # 按出现次数降序排列
print(freq.most_common(3)) # 出现次数最多的前 3 个字符
95
[ 例 ] 已知一个包含学生成绩的字典 , 求最高分、最低分、平均分 , 并查
找所有最高分学生 .
scores = {"Moo": 45, "Norman": 78, "Olson": 40, "Peerson": 96,
"Russel": 65, "Thomas": 90, "Vaughn": 78, "Westerly": 96,
"Baker": 60}
highest = max(scores.values())
lowest = min(scores.values())
average = sum(scores.values())/len(scores)
highestPerson = [name for name, score in scores.items()
if score == highest]
print('Max score:', highest)
print('Min score:', lowest)
print('Average score:', average)
print('Students with max score:', highestPerson)

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) 的创建与删除
无序可变 , 使用一对大括号界定 , 元素间以逗号分隔 .

集合中的元素不重复 , 必须是可 hash 对象 , 即不可变对象(数字、字


符串、元组等),不能包含列表、字典、集合等可变对象 .

可通过 set([iterable]) 函数创建一个 set 对象 , 其元素为 iterable 对象中


的元素 , 重复元素仅保留一个 .

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)

方法二和方法三 : 利用 set 元素和 dict 的 key 的不重复特性去除重复元


素 , 但是集合的无序特性导致所产生的 list 并不是按照原来的顺序 .
104
 利用 sort/sorted 方法的参数 key 来恢复原来的 ( 下标 ) 顺

sorted(iterable, key=None, reverse=False)
L.sort(key=None, reverse=False)
 key 为某个函数对象
# 方法二:
根据调用 key(value) 返回的值来确定顺序
newSet = set(listRandom)
noRepeat = list(newSet)
noRepeat.sort(key=listRandom.index) # 排序依据 key 为原列表的 index 函数
# noRepeat = sorted(noRepeat, key=listRandom.index)
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

中的 sorted() 函数没有 cmp 参数。 Iterable :可迭代对象;


 key 参数可以接收一个函数,该函数将作用于排序对象中的每个

值,以确定结果的顺序。
 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']]

>>> sorted(gameresult, key=itemgetter(0, 1)) # 按姓名升序,姓名相同按分数升序排序


[['Alan', 86.0, 'C'], ['Bob', 95.0, 'A'], ['Mandy', 83.5, 'A'], ['Rob', 89.3, 'E']]

>>> sorted(gameresult, key=itemgetter(1, 0)) # 按分数升序,分数相同的按姓名升序排序


[['Mandy', 83.5, 'A'], ['Alan', 86.0, 'C'], ['Rob', 89.3, 'E'], ['Bob', 95.0, 'A']]
>>> sorted(gameresult, key=itemgetter(2, 0)) # 按等级升序,等级相同的按姓名升序排序

[['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}]

>>> sorted(gameresult, key=itemgetter('wins', 'name'))


# 按’ wins’ 升序,该值相同的按’ name’ 升序排序
[{'wins': 3, 'rating': 57.0, 'name': 'David', 'losses': 5}, {'wins': 4,
'rating': 57.0, 'name': 'Carol', 'losses': 5}, {'wins': 9, 'rating': 72.8,
'name': 'Patty', 'losses': 3}, {'wins': 10, 'rating': 75.0, 'name': 'Bob',
'losses': 3}]

113

You might also like