# 免责声明:
本文内容主要是肥清大神的视频以及自己收集学习内容的整理笔记,目是主要是为了让象博主这样的老白能更好的学习编号,如有侵权,请联系博主进行删除。
5. 控制结构
5.1. 复杂的列表推导
# 两个循环的条件以内可使用列表推导式
5.2. lambda 使用
# 一次性的结果可用
# 尽可能少用
5.3. 循环中使用else
# for/while 中只有循环体正确执行没有中断时才会执行 else
# 尽可能少用
5.4. 生成器 or 列表推导
# 列表推导会全部 load 内存里, 相对省时间, 但费空间
# 生成器则不会, 相对节省内存, 但费时间(每次都要生成)
def read_lines(path: str) -> Iterator[str]:
with open(paht, 'r') as file:
for line in file:
if line in file:
if line.startswith('<<'):
yield line
lines = read_lines('lines.txt')
print(lines) # generator
for ln in lines:
print(ln)
6. Python3 中增强的 range 对象
# 节省内存
* 使用([start=0,] stop[, step=1]) 三个元素
* 无论多大的范围内存大小几乎都一样
# 可进行逻辑比较
range(100) == range(100) # True
range(100) > range(200) # False
# 可使用切片
range(1: 10)[5:] # range(6, 10)
# 速度比列表快
7. 数据结构优化
7.1. 列表/数组
# 列表是像数组一样的可变数据结构
# 列表在 Python 中排序并具有确定的大小
# 列表像数组一样是 0 索引的,并且可以容纳重复的元素
# 列表可以有效地保留数据序列以供将来迭代
7.1.1. 列表推导的特别之处
# 可以相对 for 循环加速
7.1.2. 使用列表推导而不是 map() 和 filter()
# 列表推导更简单
7.1.3. 负索引
# 快速反向访问
7.1.4. 确定可迭代性的 all 和 any
# all(): 全真为真, 一假为假
# any(): 一真为真, 全假为假
7.1.5. 使用 * 运算符操作剩余序列
# * 用于除前后变量的所有值
mylist = ['a', 'b', 'c', 'd', 'e']
(el1, el2, *remaining) = mylist
print(remaining) # ['c', 'd', 'e']
(el1, *middle, len) = mylist
print(middle) # ['b', 'c', 'd']
(*el1, leminus1, eln) = mylist
print(el1) # ['a', 'b', 'c']
7.1.6. 使用 array.array 获取基本类型数组
# 只能是一维数组
# 不常用
7.1.7. str ——不可变 unicode 字符数组
# -*- coding: UTF-8 -*-
# version: python3.12
arr = 'characters'
arr[1] = 'm' # TypeError: 'str' object does not support item assignment
7.1.8. bytearray —— 单字节可变序列
# 处理数据量不大的数组
# 可优化写入时间
7.1.9. 使用 bytes 作为不可变的单字节序列
# 0 ~ 255
# 多次引用但数值不变
# 可优化读取时间
7.2. 创建高效字典
# 字典是高度优化的数据结构
7.2.1. 获取 value 时提供默认值
# 方法: dict.get()
# 特点:
* 键不存在时
* 有默认值: 返回默认值
* 无默认值: 返回None
* 不会抛出异常
7.2.2. 使用 defaultdict 缺失键的默认值
# 方法: defaultdict()
# 特点:
* 优化速度
7.2.3. 通过字典推导优化 dict 构造
# 可以优化速度
* 不明显
7.2.4. ChainMap
# ChainMap 类用于快速链接多个映射, 以便将它们视为一个单元
* 通常比创建一个新的额外字典和运行多个 update() 调用要快得多
* 查找时, 从左到右依次搜索底层字典, 直到找到键
* 采用<分层>结构
* 只返回第一次出现的查找结果
* 插入 | 更新 | 删除仅影响添加到链中的第一个映射
# ChainMap 的惰性构造方法对写入更有效率
* 若读操作高于写操作,原来的dict的哈希查找就比较高效率
# 假设在有 X 层, 每层最多有Y个键的情况下:
* 最坏的情况下, 构造一个 ChainMap 需要 O(X), 每次查找 O(X), 而使用更新循环构造一个 dict 需要 O(XY), 每次查找需要 O(1)
7.2.4.1. 应用场景
# 用在写多读少,对写的敏感的仅应用原生Python的语言特点的应用场合
# 特别是数据量大,key多且复杂的情况下,会有优势。如果对于这些不敏感,从维护角度来看,就没有必要去用
# -*- coding: UTF-8 -*-
# version: python3.12
from collections import ChainMap
m1 = {'soccer': 100, 'basketball': 200, 'vollyball': 300}
m2 = {'tennis': 400, 'golf': 500, 'soccer': 600}
cmap = ChainMap(m1, m2)
print(cmap, type(cmap)) #
7.2.5. MappingProxyType 创建只读字典
# 在大多数实际的生产应用程序中,配置管理可以有两种类型:
* 静态的类型: 很少随时间改变的配置
* 动态的类型: 非常频繁地改变的配置
# 在大多数 Python 应用程序中,配置以字典的形式方便地存储
# 静态配置如何防止配置被修改
* 强加只读性质
# MappingProxyType 类本质上是标准 Python 字典的包装器
* 支持字典的所有读操作
* Python 中的 types 模块
* 一旦创建,就可以用作只读的字典
* 这个只读字典也可用于存储返回值并将其传递给类或模块的内部状态而无需任何外部更改或访问对象
* 在这种情况下,可以通过使用 MappingProxyType 来限制编辑,而不是创建类的副本
* 此功能仅在 Python 3 及更高版本中可用
# 高并发时代替锁的作用 —— 读写分离
* 保持共享变量/资源只读
* 修改共享变量/资源交给别一个任务
* 按顺序进行修改
* 通知只读的代理做变更
7.2.6. 排序字典的方法
# Python 3 的字典默认实现保持插入字典的键的顺序
# 实现根据value进行排序
* 将 callable 的函数或方法传递给排序方法的 key 参数
* lambda
* sorted()
* 这个可调用对象将被定义为以自定义方式比较序列的两个元素
from operator import (
itemgetter,
)
d = {'a': 300, 'b': 200, 'c': 100}
re = sorted(d)
print(re) # ['a', 'b', 'c']
re = sorted(d.values())
print(re) # [100, 200, 300]
re = sorted(d.items())
print(re) # [('a', 300), ('b', 200), ('c', 100)]
# d.items() 是一个元组, 1代表第1个元素 value
re = sorted(d.items(), key=lambda x: x[1])
print(re) # [('c', 100), ('b', 200), ('a', 300)]
# itemgetter(1) 返回一个获取第1个元素的函数
re = sorted(d.items(), key=itemgetter(1))
print(re) # [('c', 100), ('b', 200), ('a', 300)]
7.2.7. 合并字典的方法
# 从多个的字典中的键值对创建一个新的合并字典,必须制定冲突解决策略
* 字典之间可以有公共的Key
# 在 Python 中合并 n 个字典的最简单方法: update() 方法
* update() 的实现很简单
* 遍历字典的元素,将每个条目添加到结果字典中
* 如果key存在,它将覆盖key的先前值
* 任何重复key的最后一个值都将被保留,而其他的则被覆盖
* update() 调用可以链接起来,并且可以扩展到任意数量的字典
# 最优化的方法: 使用 ** 运算符来解包对象
* Python 3.5 以前仅支持一次合并两个字典
* 内置 dict() 方法
* Python 3.5 及更高版本中,** 运算符支持将多个字典合并为一个
* 直接 {} 法
* 用这种方法写的代码看起来干净且可读
* 使用 ** 运算符还可以在大型字典的情况下加快速度
* 在语言结构本身中进行了优化
fruit_price_map_gz = {'apple': 10.5, 'orange': 8.8}
fruit_price_map_sh = {'banana': 2.8, 'orange': 9.5}
fruit_price_map_bj = {'watermelon': 5.5, 'orange': 10.8}
merged_price_map = {}
merged_price_map.update(fruit_price_map_gz)
merged_price_map.update(fruit_price_map_sh)
merged_price_map.update(fruit_price_map_bj)
# 'orange' 被覆盖
print(merged_price_map) # {'apple': 10.5, 'orange': 10.8, 'banana': 2.8, 'watermelon': 5.5}
merged_price_map = dict(fruit_price_map_gz, **fruit_price_map_sh)
merged_price_map = dict(merged_price_map, **fruit_price_map_bj)
print(merged_price_map) # {'apple': 10.5, 'orange': 10.8, 'banana': 2.8, 'watermelon': 5.5}
merged_price_map = {
**fruit_price_map_sh,
**fruit_price_map_gz,
**fruit_price_map_bj,
}
print(merged_price_map) # {'apple': 10.5, 'orange': 10.8, 'banana': 2.8, 'watermelon': 5.5}
7.2.8. 漂亮打印字典
# 默认情况下,Python 将字典打印在一行中,并且不保留缩进
* 当字典很大并且存储复杂的数据时,通常打印它们的易读性会降低
# 借助 Python 中的内置 json 模块,简单地使用 json.dumps() 可以漂亮地打印具有更结构化格式的字典,使输出更清晰
* json 包中的方法仅适用于 dict 仅包含原始数据类型的情况
* 如果您在字典中存储诸如函数之类的实体,就不能处理了
* 使用 json.dumps() 的另一个缺点是它不能字符串化复杂的数据类型
* 比如集合
# Python 的另一个经典解决方案是内置的 pprint 模块
* pprint 能够打印集合之类的数据类型,并且它以可重现的顺序打印字典key
* 与 json.dumps() 相比,它在视觉上并不能很好地表示嵌套结构
# PyYaml模块也可以打印出漂亮的字典结构
* 参见 <<精彩模块-第三方>>
# 我们应该首选使用 json.dumps() 打印字典
* 因为它提高了可读性和格式
* 前提是确定它们没有非原始数据类型
7.2.9. 奇怪的表达式 !?
# Python 将 bool 视为 int 数据类型的子类型
* 大部分情况:
* True == 1 == 1.0
* False == 0
* 例外: str(bool) -> str
* str(True) -> 'True'
* str(False) -> 'False'
# 若使用 bool 值 True/False 作为字典的 key,会产生一些奇怪的现象: 出现覆盖/合并值的现象
* key: 保留第 1 个
* value: 保留最后一个
* 这是一个大坑,以免在实际生产中产生问题
dict_true = {
True: 'apple',
1: 'orange',
1.0: 'banana',
}
print(dict_true) # {True: 'banana'}
dict_false = {
False: 'apple',
0: 'orange',
0.0: 'banana',
}
print(dict_false) # {False: 'banana'}
7.2. 创建高效字典
# 字典是高度优化的数据结构
7.2.1. 获取 value 时提供默认值
# 方法: dict.get()
# 特点:
* 键不存在时
* 有默认值: 返回默认值
* 无默认值: 返回None
* 不会抛出异常
7.2.2. 使用 defaultdict 缺失键的默认值
# 方法: defaultdict()
# 特点:
* 优化速度
7.2.3. 通过字典推导优化 dict 构造
# 可以优化速度
* 不明显
7.2.4. ChainMap
# ChainMap 类用于快速链接多个映射, 以便将它们视为一个单元
* 通常比创建一个新的额外字典和运行多个 update() 调用要快得多
* 查找时, 从左到右依次搜索底层字典, 直到找到键
* 采用<分层>结构
* 只返回第一次出现的查找结果
* 插入 | 更新 | 删除仅影响添加到链中的第一个映射
# ChainMap 的惰性构造方法对写入更有效率
* 若读操作高于写操作,原来的dict的哈希查找就比较高效率
# 假设在有 X 层, 每层最多有Y个键的情况下:
* 最坏的情况下, 构造一个 ChainMap 需要 O(X), 每次查找 O(X), 而使用更新循环构造一个 dict 需要 O(XY), 每次查找需要 O(1)
7.2.4.1. 应用场景
# 用在写多读少,对写的敏感的仅应用原生Python的语言特点的应用场合
# 特别是数据量大,key多且复杂的情况下,会有优势。如果对于这些不敏感,从维护角度来看,就没有必要去用
# -*- coding: UTF-8 -*-
# version: python3.12
from collections import ChainMap
m1 = {'soccer': 100, 'basketball': 200, 'vollyball': 300}
m2 = {'tennis': 400, 'golf': 500, 'soccer': 600}
cmap = ChainMap(m1, m2)
print(cmap, type(cmap)) #
7.2.5. MappingProxyType 创建只读字典
# 在大多数实际的生产应用程序中,配置管理可以有两种类型:
* 静态的类型: 很少随时间改变的配置
* 动态的类型: 非常频繁地改变的配置
# 在大多数 Python 应用程序中,配置以字典的形式方便地存储
# 静态配置如何防止配置被修改
* 强加只读性质
# MappingProxyType 类本质上是标准 Python 字典的包装器
* 支持字典的所有读操作
* Python 中的 types 模块
* 一旦创建,就可以用作只读的字典
* 这个只读字典也可用于存储返回值并将其传递给类或模块的内部状态而无需任何外部更改或访问对象
* 在这种情况下,可以通过使用 MappingProxyType 来限制编辑,而不是创建类的副本
* 此功能仅在 Python 3 及更高版本中可用
# 高并发时代替锁的作用 —— 读写分离
* 保持共享变量/资源只读
* 修改共享变量/资源交给别一个任务
* 按顺序进行修改
* 通知只读的代理做变更
7.2.6. 排序字典的方法
# Python 3 的字典默认实现保持插入字典的键的顺序
# 实现根据value进行排序
* 将 callable 的函数或方法传递给排序方法的 key 参数
* lambda
* sorted()
* 这个可调用对象将被定义为以自定义方式比较序列的两个元素
from operator import (
itemgetter,
)
d = {'a': 300, 'b': 200, 'c': 100}
re = sorted(d)
print(re) # ['a', 'b', 'c']
re = sorted(d.values())
print(re) # [100, 200, 300]
re = sorted(d.items())
print(re) # [('a', 300), ('b', 200), ('c', 100)]
# d.items() 是一个元组, 1代表第1个元素 value
re = sorted(d.items(), key=lambda x: x[1])
print(re) # [('c', 100), ('b', 200), ('a', 300)]
# itemgetter(1) 返回一个获取第1个元素的函数
re = sorted(d.items(), key=itemgetter(1))
print(re) # [('c', 100), ('b', 200), ('a', 300)]
7.2.7. 合并字典的方法
# 从多个的字典中的键值对创建一个新的合并字典,必须制定冲突解决策略
* 字典之间可以有公共的Key
# 在 Python 中合并 n 个字典的最简单方法: update() 方法
* update() 的实现很简单
* 遍历字典的元素,将每个条目添加到结果字典中
* 如果key存在,它将覆盖key的先前值
* 任何重复key的最后一个值都将被保留,而其他的则被覆盖
* update() 调用可以链接起来,并且可以扩展到任意数量的字典
# 最优化的方法: 使用 ** 运算符来解包对象
* Python 3.5 以前仅支持一次合并两个字典
* 内置 dict() 方法
* Python 3.5 及更高版本中,** 运算符支持将多个字典合并为一个
* 直接 {} 法
* 用这种方法写的代码看起来干净且可读
* 使用 ** 运算符还可以在大型字典的情况下加快速度
* 在语言结构本身中进行了优化
fruit_price_map_gz = {'apple': 10.5, 'orange': 8.8}
fruit_price_map_sh = {'banana': 2.8, 'orange': 9.5}
fruit_price_map_bj = {'watermelon': 5.5, 'orange': 10.8}
merged_price_map = {}
merged_price_map.update(fruit_price_map_gz)
merged_price_map.update(fruit_price_map_sh)
merged_price_map.update(fruit_price_map_bj)
# 'orange' 被覆盖
print(merged_price_map) # {'apple': 10.5, 'orange': 10.8, 'banana': 2.8, 'watermelon': 5.5}
merged_price_map = dict(fruit_price_map_gz, **fruit_price_map_sh)
merged_price_map = dict(merged_price_map, **fruit_price_map_bj)
print(merged_price_map) # {'apple': 10.5, 'orange': 10.8, 'banana': 2.8, 'watermelon': 5.5}
merged_price_map = {
**fruit_price_map_sh,
**fruit_price_map_gz,
**fruit_price_map_bj,
}
print(merged_price_map) # {'apple': 10.5, 'orange': 10.8, 'banana': 2.8, 'watermelon': 5.5}
7.2.8. 漂亮打印字典
# 默认情况下,Python 将字典打印在一行中,并且不保留缩进
* 当字典很大并且存储复杂的数据时,通常打印它们的易读性会降低
# 借助 Python 中的内置 json 模块,简单地使用 json.dumps() 可以漂亮地打印具有更结构化格式的字典,使输出更清晰
* json 包中的方法仅适用于 dict 仅包含原始数据类型的情况
* 如果您在字典中存储诸如函数之类的实体,就不能处理了
* 使用 json.dumps() 的另一个缺点是它不能字符串化复杂的数据类型
* 比如集合
# Python 的另一个经典解决方案是内置的 pprint 模块
* pprint 能够打印集合之类的数据类型,并且它以可重现的顺序打印字典key
* 与 json.dumps() 相比,它在视觉上并不能很好地表示嵌套结构
# PyYaml模块也可以打印出漂亮的字典结构
* 参见 <<精彩模块-第三方>>
# 我们应该首选使用 json.dumps() 打印字典
* 因为它提高了可读性和格式
* 前提是确定它们没有非原始数据类型
7.2.9. 奇怪的表达式 !?
# Python 将 bool 视为 int 数据类型的子类型
* 大部分情况:
* True == 1 == 1.0
* False == 0
* 例外: str(bool) -> str
* str(True) -> 'True'
* str(False) -> 'False'
# 若使用 bool 值 True/False 作为字典的 key,会产生一些奇怪的现象: 出现覆盖/合并值的现象
* key: 保留第 1 个
* value: 保留最后一个
* 这是一个大坑,以免在实际生产中产生问题
dict_true = {
True: 'apple',
1: 'orange',
1.0: 'banana',
}
print(dict_true) # {True: 'banana'}
dict_false = {
False: 'apple',
0: 'orange',
0.0: 'banana',
}
print(dict_false) # {False: 'banana'}
7.3. 集合处理
# set 是不允许重复元素的对象的无序集合
# 在正确的集合实现中:
* 检测成员是否存在将在 O(1) 时间内运行
* 并集/交集/差集/子集操作平均需要 O(n) 时间
# Python 标准库中包含的集合实现遵循这些性能特征
# 集合在 Python 中得到特殊处理, 并具有一些语法糖, 使它们易于创建
* <大括号集合表达式语法>和<集合推导>允许您方便地定义新的集合实例
* 创建一个空集需要调用 set() 构造函数
* 使用空花括号 {} 是会创建一个空字典
* 集合可以称为有键但没有值的字典
# set 类还实现了 Iterable 接口
* set 可以在 for 循环中使用或作为 in 语句的主题
7.3.1. 理解和使用数学集合运算
# 了解基本的数学集合运算将有助于理解 Python 中集合的正确用法
* 集合 A 和 B 相关的一些操作如下:
* 并集: A 和 B 中的元素
* 语法: A | B
* 交集: A 和 B 共有的元素
* 语法: A & B
* 差集: A 中有但 B 中没有的元素
* 语法: A – B
* 不可交换
* 相对补集??
* 对称差异: A 或 B 中的元素排除掉共同元素
* 语法: A^B
# 技巧:
* 处理数据列表时, 一项常见任务是查找出现在所有列表中的元素
* 需要根据序列成员的属性从两个或多个序列中选择元素时, 应该选择使用集合
* 使用<集合运算>
7.3.1.1. 集合运算
programming_languages = {'C#', 'Go', 'Java', 'Python', 'Ruby'}
dynamic_languages = {'Ruby', 'Python', 'JavaScript', 'Lua'}
# 并集
re = programming_languages | dynamic_languages
print(re, ) # {'Python', 'Ruby', 'JavaScript', 'C#', 'Go', 'Lua', 'Java'}
# 交集
re = programming_languages & dynamic_languages
print(re, ) # {'Python', 'Ruby'}
# 差集
re = programming_languages - dynamic_languages
print(re, ) # {'Java', 'Go', 'C#'}
re = dynamic_languages - programming_languages
print(re, ) # {'JavaScript', 'Lua'}
# 对称差异
re = programming_languages ^ dynamic_languages
print(re, ) # {'JavaScript', 'C#', 'Go', 'Lua', 'Java'}
7.3.1.2. 多列表取值
backend_developers = ['John', 'Rose', 'Jane', 'Steven']
frontend_developers = ['May', 'Rose', 'Jane', 'Jonny']
full_stack_developers = list(set(backend_developers) & set(frontend_developers))
print(full_stack_developers)
7.3.2. 集合推导
# 集合推导在语法上与 dict() 理解的语法相同
* 是一个被低估的功能
* 无值字典
# 使用推导式创建 Pythonic 数据结构的重要性再怎么强调也不为过
* 尤其是当数据的大小相当大时
* 不仅由于底层优化而提供了性能加速, 而且使得代码更具可读性
7.3.3. 集合高效检测列表
# 这里讨论的集合的 & 运算符的扩展
* 有助于找到两组之间的共同元素
# list() 和 set() 方法也分别接受集合和列表作为参数
# 当只关心出现在两个列表中的元素是否有共同的元素存在时
* 可以使用<非空列表的真值>来创建清晰简洁的条件语句
* 效率出奇的高
import dis
from timeit import timeit
# 判断两个列表中是否有公共元素
favorite_names = [f'name - {i}' for i in range(1000)]
other_names = [f'name - {i}' for i in range(500, 1500)]
* 方法 1:
def are_common_names(one_names: list, other_names: list) -> bool:
for name in one_names:
if name in other_names:
return True
return False
re1 = timeit(stmt='are_common_names(one_names, other_names)',
setup='from __main__ import are_common_names; ' # 从主模块<当前运行模块>中导入 要运行的函数
'from __main__ import favorite_names; ' # 从主模块<当前运行模块>中导入 函数用到的实参, 具体数值也可直接写上
'from __main__ import other_names; '
'one_names = favorite_names;' # 指定形参和实参的对应关系
'other_names = other_names', # 形参和实参同名时可省略
number=100, # 适当调整程序执行的循环数量
)
print(re1,)
* 方法 2:
def are_common_name_set_operation(
one_names: list, other_names: list
) -> bool:
return len(set(one_names) & set(other_names)) > 0
re2 = timeit(stmt='are_common_name_set_operation(one_names, other_names)',
setup='from __main__ import are_common_name_set_operation; ' # 从主模块<当前运行模块>中导入 要运行的函数
'from __main__ import favorite_names; ' # 从主模块<当前运行模块>中导入 函数用到的实参, 具体数值也可直接写上
'from __main__ import other_names; '
'one_names = favorite_names;' # 指定形参和实参的对应关系
'other_names = other_names', # 形参和实参同名时可省略
number=100, # 适当调整程序执行的循环数量
)
print(re2,)
print(f'<方法1>消耗的时间是<方法2>的{re1/re2}倍') # 43.178728193062405倍
* 分析一下原因
print('-- dis(are_common_names)--')
dis.dis(are_common_names)
print('-- dis(are_common_name_set_operation)--')
dis.dis(are_common_name_set_operation)
-- dis(are_common_names)-- | -- dis(are_common_name_set_operation)-- | |
---|---|---|
10 0 RESUME 0 | 28 0 RESUME 0 | |
11 2 LOAD_FAST 0 (one_names) | 31 2 LOAD_GLOBAL 1 (NULL + len) | |
4 GET_ITER | 14 LOAD_GLOBAL 3 (NULL + set) | |
>> 6 FOR_ITER 9 (to 26) | 26 LOAD_FAST 0 (one_names) | |
8 STORE_FAST 2 (name) | 28 PRECALL 1 | |
32 CALL 1 | ||
12 10 LOAD_FAST 2 (name) | 42 LOAD_GLOBAL 3 (NULL + set) | |
12 LOAD_FAST 1 (other_names) | 54 LOAD_FAST 1 (other_names) | |
14 CONTAINS_OP 0 | 56 PRECALL 1 | |
16 POP_JUMP_FORWARD_IF_FALSE 3 (to 24) | 60 CALL 1 | |
70 BINARY_OP 1 (&) | ||
13 18 POP_TOP | 74 PRECALL 1 | |
20 LOAD_CONST 1 (True) | 78 CALL 1 | |
22 RETURN_VALUE | 88 LOAD_CONST 1 (0) | |
90 COMPARE_OP 4 (>) | ||
12 >> 24 JUMP_BACKWARD 10 (to 6) | 96 RETURN_VALUE | |
14 >> 26 LOAD_CONST 2 (False) | ||
28 RETURN_VALUE |
7.3.4. Iterables 高效去重
# 列表和字典等广泛使用的数据结构通常具有重复值
# 集合 set 已成为正确的去重候选者:
* 一个集合 set 只能容纳不重复的元素
* 将已有的元素添加到集合 set 中将会被忽略
* 可以从任何实现了 Hashable 的元素构建集合 set
# 在 Python 中, 集合 set 与 list 都是是 Iterable
* 在循环 | 列表推导中可以互换使用
# 集合 set 去重既高效又简单
from timeit import timeit
list_of_games = [
'PES2021',
'FIFA22',
'1943',
'1943 Kai',
'Super Street FighterII',
'1943',
'PES2021',
'FIFA22',
]
# 列表去重
* 方法1:
def get_unique_of_games(games):
unique_of_games = []
for game in games:
if game not in unique_of_games:
unique_of_games.append(game)
re1 = timeit(stmt='get_unique_of_games(games*10000)',
setup='from __main__ import get_unique_of_games;'
'from __main__ import list_of_games;'
'games = list_of_games;',
number=1,
)
print(re1)
* 方法2:
def get_unique_of_games_with_set(games):
result = list(set(games))
re2 = timeit(stmt='get_unique_of_games_with_set(games*10000)',
setup='from __main__ import get_unique_of_games_with_set;'
'from __main__ import list_of_games;'
'games = list_of_games;',
number=1,
)
print(re2, )
print(f'{re1/re2}倍') # 4.272562027579992倍
7.3.5. frozenset 创建不可变集合
# frozenset 类可以在需要时创建一组在整个程序执行过程中唯一且不变的只读集合 set
* 可以防止对集进行任何修改
* 本质上是静态的
* 只能查询它们的元素
* 内置集合类型
# frozenset 的优势:
* 可以将它们用作字典中的键/另一个集合的元素
* 因为它们的不变性, 自然就可以hashable, 作为字典的key是没有问题的
# 对于修改集合的操作, fronzenset 都会失败
# fozenset 支持所有集合操作而且也是无序的
7.3.6. Counter
# collections.Counter 类可以在保持集合实体的唯一性的同时又能处理集合中任何元素的多个实例
* 也被称为多 multiset 或 bags 的数据结构
# 若想要跟踪集合中元素出现少次以及它在集合中的存在性, Counter就很有用
标签:map,Pythonic,之阅,Python,price,names,print,字典
From: https://www.cnblogs.com/matrix-1999/p/18223821