Python的数据结构,推导式、迭代器和生成器
本文最后更新于 2026年5月4日
未完待续
【新年开篇】让我们拿出跃马扬鞭的勇气,激发万马奔腾的活力,保持马不停蹄的干劲,一起为梦想奋斗、为幸福打拼,把宏伟愿景变成美好现实。
1.概述
在Python中,有四种常见的数据结构
| 数据结构 | 是否可变 | 是否允许重复 | 是否有序 | 定义符号 |
|---|---|---|---|---|
| 列表(List) | 可变 | 允许 | 有序 | [] |
| 元组(Tuple) | 不可变 | 允许 | 有序 | () |
| 字典(Dict) | 可变 | 键不允许,值允许 | 有序 | {} |
| 集合(Set) | 可变 | 不允许 | 无序 | {} |
2.列表(List)
列表是一种有序的数据结构,元素写在[]中间,用,隔开通过下标访问。
列表创建有三种,直接创建,通过list()方法,以及推导式。
列表的特点:
- 可以被索引(从左到右和从右到左)和切片(substring)
- 可以使用
+操作符进行拼接 - 列表中的元素是可变的
- 元素可以是任意类型
- 元素允许重复
2.1 创建
#直接创建
list1 = [1,2,3,4,5]
list2 = ['abc', 2, 1.55]
python还有几种常见创建list方式:
list()方法创建一个空的集合
empty_list = list()
print(empty_list)用list()方法从字符串创建数组
s = 'hello'
l = list(s)
print(l) #['h', 'e', 'l', 'l', 'o']从set集合创建
s = {1,2,3,4}
l = list(s)
print(l) #[1, 2, 3, 4]从tuple元组创建
t = (1,2,3,4)
l = list(t)
print(l) #[1, 2, 3, 4]从dic字典创建,只取每个key作为元素
d = {'a':1, 'b':2, 'c':3}
l = list(d)
print(l) #['a', 'b', 'c']从dic字典创建,取每个键值对作为元素
d = {'a':1, 'b':2, 'c':3}
l = list(d.items())
print(l) #[('a', 1), ('b', 2), ('c', 3)]从dic字典创建,取每个value作为元素
d = {'a':1, 'b':2, 'c':3}
l = list(d.values())
print(l) #[1, 2, 3]通过range()创建list
sample_list = list(range(10))
print(sample_list) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]带类型标识符
from typing import List, Union
# 只包含整数的列表
lst1: List[int] = [1, 2, 3, 4, 5]
# 包含其他类型
lst2: List[ Union[int, str, List[int] ] ] = [1, 2, 3, 4, '5']2.2 列表常见方法
索引和切片
# 索引 => 1
print(list1[0])
# 第2到第4的元素,不含第4个 => [2, 3]
print(list1[1:3])
# 从第3个元素开始到末尾 => [3, 4, 5]
print(list1[2:])
# list1复制成两份拼接一起 => [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
print(list1 * 2)
# 拼接 => [1, 2, 3, 4, 5, 'abc', 2, 1.55]
print(list1 + list2)Python列表可以倒序索引,从-1开始,且元素可变
list1[-1] = 100
print(list1[-1]) #100列表可变,因此可以进行添加和删除元素等操作
删除第一个值为2的元素
l = [1,2,3,4,5,2]
l.remove(2)
print(l) #[1, 3, 4, 5, 2]追加元素
l = [1,2,3,4,5]
l.append(4)
print(l) #[1, 2, 3, 4, 5, 4]在某个元素前添加
l = [1,2,3,4,5]
l.insert(3, 'a')
print(l) #[1, 2, 3, 'a', 4, 5]加号运算,两个列表拼接成为一个全新的列表对象
list1 = [1,2,3]
list2 = [3,4,5]
list3 = list1 + list2
print(list1)
print(list2)
print(list3)
print(id(list1))
print(id(list2))
print(id(list3))[1, 2, 3]
[3, 4, 5]
[1, 2, 3, 3, 4, 5]
2575803669824
2575803939264
2575796778880删除指定位置的元素并返回
l = [1,2,3,4,5,2]
sl = l.pop(2) # 删除指定位置的元素并返回
print(sl)
print(l)3
[1, 2, 4, 5, 2]长度,最大值,最小值,求和
list1 = [6, 2, 4, 7, 8]
print(f"获取列表长度: {len(list1)}")
print(f"列表的最大值: {max(list1)}")
print(f"列表的最小值: {min(list1)}")
print(f"列表的所有元素的和: {sum(list1)}") 获取列表长度: 5
列表的最大值: 8
列表的最小值: 2
列表的所有元素的和: 27排序,反转
sort_list=[10,8,7,1,20]
sort_list.sort() # 列表排序
print(f"列表排序: {sort_list}")
sort_list.reverse() # 列表反转
print(f"列表反转: {sort_list}") 列表排序: [1, 7, 8, 10, 20]
列表反转: [20, 10, 8, 7, 1]2.3 遍历列表
1.使用for循环遍历列表
lst=[6, 2, 3, 4, 7, 8]
for item in lst:
print(f"遍历列表元素: {item}") 遍历列表元素: 6
遍历列表元素: 2
遍历列表元素: 3
遍历列表元素: 4
遍历列表元素: 7
遍历列表元素: 82.下标遍历
lst=[6, 2, 3, 4, 7, 8]
for i in range(len(lst)):
print(f"使用下标遍历列表元素: {lst[i]}") 使用下标遍历列表元素: 6
使用下标遍历列表元素: 2
使用下标遍历列表元素: 3
使用下标遍历列表元素: 4
使用下标遍历列表元素: 7
使用下标遍历列表元素: 83.使用enumerate函数遍历列表,可以同时遍历下标和元素,还可以start=指定从哪个下标开始
lst=[6, 2, 3, 4, 7, 8]
for index, item in enumerate(lst):
print(f"使用enumerate函数遍历列表元素: {index} -> {item}")
for index, item in enumerate(lst, start=2):
print(f"使用enumerate函数遍历列表元素 start=2 : {index} -> {item}")使用enumerate函数遍历列表元素: 0 -> 6
使用enumerate函数遍历列表元素: 1 -> 2
使用enumerate函数遍历列表元素: 2 -> 3
使用enumerate函数遍历列表元素: 3 -> 4
使用enumerate函数遍历列表元素: 4 -> 7
使用enumerate函数遍历列表元素: 5 -> 8
使用enumerate函数遍历列表元素 start=2 : 2 -> 6
使用enumerate函数遍历列表元素 start=2 : 3 -> 2
使用enumerate函数遍历列表元素 start=2 : 4 -> 3
使用enumerate函数遍历列表元素 start=2 : 5 -> 4
使用enumerate函数遍历列表元素 start=2 : 6 -> 7
使用enumerate函数遍历列表元素 start=2 : 7 -> 84.zip函数同时遍历多个列表
list_a = [1, 2, 3]
list_b = [4, 5, 6]
for item_a, item_b in zip(list_a, list_b):
print(f"使用zip函数遍历多个列表元素: {item_a}, {item_b}") #使用zip函数遍历多个列表元素: 1, 4
使用zip函数遍历多个列表元素: 2, 5
使用zip函数遍历多个列表元素: 3, 63.元组(Tuple)
元组是一种和列表相似的数据结构,元素是任意类型,有序,允许重复,区别是:元组元素不可变
3.1 创建
几种简单创建方式
tup = tuple() #通过tuple()方法创建
tup = () #空元组
tup = (1, 2, 3) #创建元组
tup = (1,) # 元组内只有一个元素,结尾要加逗号
tup = 1, 2, 3 #一种不被推荐的创建方式
tup = (1, "hello", 3.14, True) #支持不同类型
tup = (1, 2, 2, 3, 3, 3) # 重复元素从其他数据结构创建
# 使用tuple()函数接收列表创建元组
tup = tuple([1, 2, 3])
print("使用tuple()函数接收列表参数,创建元组:", tup)
# 使用tuple()函数接收字符串创建元组
tup = tuple("hello")
print("使用tuple()函数接收字符串作为参数,创建元组:", tup)
# 使用tuple()函数接收集合创建元组
tup = tuple({1, 2, 3})
print("使用tuple()函数接收集合作为参数,创建元组:", tup)
# 使用tuple()函数接收元组创建元组
from_tuple = (1, 2, 3)
tup = tuple(from_tuple)
print("使用tuple()函数接收元组作为参数,创建元组:", tup)
# 使用tuple()函数接收字典创建元组,字典的key值会作为元组的元素
tup = tuple({"a": 1, "b": 2})
print("使用tuple()函数接收字典作为参数,创建元组:", tup)
# 使用tuple()函数接收字典的values创建元组
from_dict = {"a": 1, "b": 2}
tup = tuple(from_dict.values())
print("使用tuple()函数接收字典的values作为参数,创建元组:", tup)
# 使用tuple()函数接收字典的items创建元组
tup = tuple(from_dict.items())
print("使用tuple()函数接收字典的items作为参数,创建元组:", tup)
使用tuple()函数接收列表参数,创建元组: (1, 2, 3)
使用tuple()函数接收字符串作为参数,创建元组: ('h', 'e', 'l', 'l', 'o')
使用tuple()函数接收集合作为参数,创建元组: (1, 2, 3)
使用tuple()函数接收元组作为参数,创建元组: (1, 2, 3)
使用tuple()函数接收字典作为参数,创建元组: ('a', 'b')
使用tuple()函数接收字典的values作为参数,创建元组: (1, 2)
使用tuple()函数接收字典的items作为参数,创建元组: (('a', 1), ('b', 2))带类型标识符创建
from typing import Tuple
# 包含整数、字符串、布尔值的元组
tup: Tuple[int, str, bool, List[int] ] = (25, "z3", True)3.2 常见方法
1.访问
tup = (1, 2, 3)
tup[0]2.元组元素不可变,下面程序会出错
tup = (1, 2)
tup[1] = 5 ❌元组中元素的idhash不可变,但是内容可变,例如元组
([1, 2], 3)中的list[1, 2]可以追加和编辑元素
3.索引和切片
tup = ('a', 'b', 'c')
print(f"元组访问有序性: {tup}")
print(f"元组支持索引: {tup[0]}")
print(f"元组支持索引: {tup[-2]}")
print(f"元组支持切片:{tup[1:3]}") 元组访问有序性: ('a', 'b', 'c')
元组支持索引: a
元组支持索引: b
元组支持切片:('b', 'c')4.计算,长度,最大值,最小值,求和,排序
tup=(1,2,3,4,5)
# 元组相加
print(f"元组相加: {tup + (6, 7, 8)}")
# 元组相乘
print(f"元组相乘: {tup * 2}")
# 元组的成员运算
print(f"成员运算: {2 in tup}")
# 元组的长度
print(f"元组的长度: {len(tup)}")
# 最大值和最小值和求和
print(f"元组的最大值: {max(tup)}")
print(f"元组的最小值: {min(tup)}")
print(f"元组的求和: {sum(tup)}")
# 排序
tup = tuple(sorted((5,3, 1, 4, 2)))
print(f"元组的排序: {tup}") 元组相加: (1, 2, 3, 4, 5, 6, 7, 8)
元组相乘: (1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
成员运算: True
元组的长度: 5
元组的最大值: 5
元组的最小值: 1
元组的求和: 15
元组的排序: (1, 2, 3, 4, 5)3.3 遍历元组
1.使用for循环遍历元组
tup = (1, 2, 3, 4, 5)
for item in tup:
print(f"遍历元组元素: {item}") 遍历元组元素: 1
遍历元组元素: 2
遍历元组元素: 3
遍历元组元素: 4
遍历元组元素: 52.使用下标遍历元组
tup = (1, 2, 3, 4, 5)
for i in range(len(tup)):
print(f"使用下标遍历元组元素: {tup[i]}")使用下标遍历元组元素: 1
使用下标遍历元组元素: 2
使用下标遍历元组元素: 3
使用下标遍历元组元素: 4
使用下标遍历元组元素: 53.使用enumerate函数遍历元组
tup = (1, 2, 3, 4, 5)
for index, item in enumerate(tup):
print(f"使用enumerate函数遍历元组元素: 索引 {index}, 元素 {item}")使用enumerate函数遍历元组元素: 索引 0, 元素 1
使用enumerate函数遍历元组元素: 索引 1, 元素 2
使用enumerate函数遍历元组元素: 索引 2, 元素 3
使用enumerate函数遍历元组元素: 索引 3, 元素 4
使用enumerate函数遍历元组元素: 索引 4, 元素 54.将元组转换为列表遍历
tup = (1, 2, 3, 4, 5)
traverse_list = list(tup)
for item in traverse_list:
print(f"将元组转换为列表遍历: {item}")将元组转换为列表遍历: 1
将元组转换为列表遍历: 2
将元组转换为列表遍历: 3
将元组转换为列表遍历: 4
将元组转换为列表遍历: 55.使用生成器遍历元组
tup = (1, 2, 3, 4, 5)
for item in (x for x in tup):
print(f"使用生成器遍历元组元素: {item}")使用生成器遍历元组元素: 1
使用生成器遍历元组元素: 2
使用生成器遍历元组元素: 3
使用生成器遍历元组元素: 4
使用生成器遍历元组元素: 54.集合(Set)
set是一种无序,可变的数据类型,可包含任意类型,元素唯一不可重复,重复的元素将被自动去重,类似Java中的HashSet
set支持交集,并集,差集等集合操作
set不支持索引和切片
4.1 创建
常见创建
# 使用花括号创建集合
s = {1, 2, 3}
# 使用set()函数创建空集合
s = set()
# 可以包含任意类型
s = {1, "hello", 3.14, True}
s = {1, 2, 2, 3, 3, 3} #集合不允许重复元素,3会被自动去重从字符串创建
s = set("hello")
print("使用set()函数接收字符串作为参数,创建集合:", s)使用set()函数接收字符串作为参数,创建集合: {'h', 'o', 'e', 'l'}从其他数据结构创建
# 使用set()函数接收列表创建集合
from_list=[1, 2, 3]
s = set(from_list)
print("使用set()函数接收列表参数,创建集合:", s)
# 使用set()函数接收元组创建集合
from_tuple = (1, 2, 3)
s = set(from_tuple)
print("使用set()函数接收元组作为参数,创建集合:", s)
# 使用set()函数接收字典创建集合
from_dict = {"a": 1, "b": 2}
s = set(from_dict)
print("使用set()函数接收字典作为参数,创建集合:", s)
# 使用set()函数接收字典的values创建集合
s = set(from_dict.values())
print("使用set()函数接收字典的values作为参数,创建集合:", s)
# 使用set()函数接收字典的items创建集合
s = set(from_dict.items())
print("使用set()函数接收字典的items作为参数,创建集合:", s)
# 5) 使用set()函数接收集合创建集合
from_set = {1, 2, 3}
s = set(from_set)
print("使用set()函数接收集合作为参数,创建集合:", s)
使用set()函数接收列表参数,创建集合: {1, 2, 3}
使用set()函数接收元组作为参数,创建集合: {1, 2, 3}
使用set()函数接收字典作为参数,创建集合: {'b', 'a'}
使用set()函数接收字典的values作为参数,创建集合: {1, 2}
使用set()函数接收字典的items作为参数,创建集合: {('a', 1), ('b', 2)}
使用set()函数接收集合作为参数,创建集合: {1, 2, 3}从range函数创建
from_range = range(5)
s = set(from_range)
print("使用set()函数接收range对象作为参数,创建集合:", s) 使用set()函数接收range对象作为参数,创建集合: {0, 1, 2, 3, 4}从推导式和生成器创建
# 使用set()函数接收生成器创建集合
from_generator = (x for x in range(5))
s = set(from_generator)
print("使用set()函数接收生成器作为参数,创建集合:", s)
# 使用集合推导式创建集合
s = {x for x in range(5)}
print("使用集合推导式创建集合:", s) 使用set()函数接收生成器作为参数,创建集合: {0, 1, 2, 3, 4}
使用集合推导式创建集合: {0, 1, 2, 3, 4}带类型标识符创建
from typing import Set, Union
# 只包含字符串的集合
s1: Set[ Union[str, int, List[int] ] ] = {"z3", "li4", "w5", 8}
# 只包含字符串的集合
s2: Set[ str ] = {"z3", "li4", "w5"}4.2 常见方法
1.增删改,长度,最值,求和,排序
s = {1, 2, 3, 4, 5}
# 集合添加元素
s.add(6)
print(f"集合添加元素: {s}")
# 删除集合存在元素
s.remove(3)
print(f"集合删除元素: {s}")
# 集合的成员检测
print(f"集合的成员检测: {4 in s}")
print(f"集合的成员检测: {8 in s}")
# 集合的长度
print(f"集合的长度: {len(s)}")
# 集合的最大值和最小值和求和
print(f"集合的最大值: {max(s)}")
print(f"集合的最小值: {min(s)}")
print(f"集合的求和: {sum(s)}")
# 集合的排序
sorted_set = sorted(s)
print(f"集合的排序: {sorted_set}")
# 删除集合不存在元素
# s.remove(8) # ❌ 会抛出 KeyError 异常集合添加元素: {1, 2, 3, 4, 5, 6}
集合删除元素: {1, 2, 4, 5, 6}
集合的成员检测: True
集合的成员检测: False
集合的长度: 5
集合的最大值: 6
集合的最小值: 1
集合的求和: 18
集合的排序: [1, 2, 4, 5, 6]2.交集并集差集
# 集合的交集
set_a = {1, 2, 3, 4, 5}
set_b = {4, 5, 6, 7, 8}
intersection_set = set_a.intersection(set_b)
print(f"集合的交集: {intersection_set}")
# 集合的并集
union_set = set_a.union(set_b)
print(f"集合的并集: {union_set}")
# 集合的差集
difference_set = set_a.difference(set_b)
print(f"集合的差集: {difference_set}") 集合的交集: {4, 5}
集合的并集: {1, 2, 3, 4, 5, 6, 7, 8}
集合的差集: {1, 2, 3}3.比较
==左右集合元素相同<左是右的真子集<=左是右的子集
- 子集 对于两个集合 ( A ) 和 ( B ),如果 ( A ) 中的每一个元素都是 ( B ) 中的元素,那么称 ( A ) 是 ( B ) 的子集
- 真子集 如果 ( A ) 是 ( B ) 的子集,并且 ( A ≠ B )(即 ( A ) 至少比 ( B ) 少一个元素),那么称 ( A ) 是 ( B ) 的真子集
print( {1, 2, 3, 4, 5} == {1, 2, 3, 4, 5} ) # True 集合元素相同
print( {1, 2, 3, 4, 5} < {1, 2, 3, 4, 5} ) # False 不是真子集
print( {1, 2, 3, 4, 5} <= {1, 2, 3, 4, 5} ) # True 是子集
print( {1, 2, 3, 5} < {1, 2, 3, 4, 5} ) # True 是真子集python集合的子集真子集比较,可用于权限标识比较
4.3 遍历
1.使用for循环遍历集合
set_a = {1, 2, 3, 4, 5}
for e in set_a:
print(f"遍历集合元素: {e}") 遍历集合元素: 1
遍历集合元素: 2
遍历集合元素: 3
遍历集合元素: 4
遍历集合元素: 52.enumerate遍历集合
for index, item in enumerate(set_a):
print(f"使用enumerate遍历集合元素: {index} -> {item}") 使用enumerate遍历集合元素: 0 -> 1
使用enumerate遍历集合元素: 1 -> 2
使用enumerate遍历集合元素: 2 -> 3
使用enumerate遍历集合元素: 3 -> 4
使用enumerate遍历集合元素: 4 -> 53.转换为list遍历
set不可直接像list那样
for i in range(len(lst))下标遍历,因为没有顺序
set_list = list(set_a)
for item in set_list:
print(f"使用列表遍历集合元素: {item}")使用列表遍历集合元素: 1
使用列表遍历集合元素: 2
使用列表遍历集合元素: 3
使用列表遍历集合元素: 4
使用列表遍历集合元素: 54.zip函数遍历
set_a = {1, 2, 3}
set_b = {4, 5, 6}
for item_a, item_b in zip(set_a, set_b):
print(f"使用zip遍历多个集合元素: {item_a}, {item_b}")使用zip遍历多个集合元素: 1, 4
使用zip遍历多个集合元素: 2, 5
使用zip遍历多个集合元素: 3, 65.字典(Dict)
待续
6.推导式 (Comprehension)
推导式是一种独特的数据处理方式,将一个可迭代对象(列表,元组,集合,字符串)的元素,通过某种条件运算或筛选后,构建成一个新的数据序列的结构体。类似Java中的Stream API。
Python支持各种数据结构的推导式。
6.1 列表推导式
大致形式:
[列表生成元素表达式 for 变量 in 列表][列表生成元素表达式 for 变量 in 列表 if 条件]
例💡:从list:lst中提取所有元素,通通扩大十倍
lst = [1,2,3,4,5,6,7,8,9,0]
sub_list = [s*10 for s in lst ]
print(sub_list) #[10, 20, 30, 40, 50, 60, 70, 80, 90, 0]例💡:带条件的推导式,从list:lst中提取所有偶数,生成新的list:sub_list
lst = [1,2,3,4,5,6,7,8,9,0]
sub_list = [s for s in lst if s % 2 == 0 ]
print(sub_list) #[2, 4, 6, 8, 0]例💡:提取所有偶数,并将它们乘以10
lst = [1,2,3,4,5,6,7,8,9,0]
sub_list = [s*10 for s in lst if s % 2 == 0 ]
print(sub_list) #[20, 40, 60, 80, 0]例💡:0-4的5个数中,筛选出比2大的,对每个进行加3
lst = [x+3 for x in range(5) if x > 2]
print(lst) #[6, 7]例💡:包含多个循环的列表推导式
continue1 = [1, 2, 3]
continue2 = ["a", "b", "c"]
lst = [(i, j) for i in continue1 for j in continue2]
print(lst) #[(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b'), (2, 'c'), (3, 'a'), (3, 'b'), (3, 'c')]6.2 元组推导式
⚠️ 严格来讲没有元组推导式,元组推导式得到的是生成器对象
大致形式:(列表生成元素表达式 for 变量 in 列表)(列表生成元素表达式 for 变量 in 列表 if 条件)
例💡:根据列表,通过推导式生成一个元组
⚠️ 元组比较特殊,生成的对象是一个generator object生成器而不是元组本身,还需要
tuple()函数转换为元组对象,且tuple()函数转换为元组对象前,不可对生成器对象进行迭代
lst = [1,2,3,4,5,6,7,8,9,0]
tup = (s*10 for s in lst if s % 2 == 0)
print( tup ) # <generator object <genexpr> at 0x000001CDE7A6BC60>
print( tuple(tup) ) # (20, 40, 60, 80, 0)6.3 集合推导式
大致形式:{列表生成元素表达式 for 变量 in 列表}{列表生成元素表达式 for 变量 in 列表 if 条件}
例💡:提取偶数
lst = [1,2,3,4,5,6]
sub_list = {x for x in lst if x % 2 == 0}
print( sub_list) #{2, 4, 6}6.4 字典推导式
大致形式:{列表生成key元素表达式:列表生成value元素表达式 for 变量 in 列表}{列表生成key元素表达式:列表生成value元素表达式 for 变量 in 列表 if 条件}
例💡:将列表中各字符串值为键,各字符串的长度为值,组成键值对
myList = ['Google','Oracle', 'Taobao','Baidu']
dic = {k:len(k) for k in myList}
print(dic) # {'Google': 6, 'Oracle': 6, 'Taobao': 6, 'Baidu': 5}7.迭代器 (Iterator)
迭代器是访问集合元素的一种方式,是一个可以记住遍历位置的对象,从集合的第一个元素开始访问,直到所有元素被访问完结束,迭代器只会前进不能后退。
迭代器有两个基本方法iter()和next()。
字符串,列表或元组对象都可用于创建迭代器。
例💡:创建迭代器
iter(lst)就是创建了一个迭代器对象,通过next(it)不断获取下一个元素,如果获取到最后一个完成还要继续获取,则报错StopIteration(迭代器对象的一次性)
lst=[1,2,3,4]
it = iter(lst) # 创建迭代器对象
print (next(it)) # 1
print (next(it)) # 2
print (next(it)) # 3
print (next(it)) # 4
print (next(it)) #❌ StopIteration例💡:迭代器对象可以使用常规for语句进行遍历
tup=(1,2,3,4)
it = iter(tup)
for e in it:
print (e, end=" ")例💡:迭代器对象的一次性使用,无论怎么遍历,已经遍历的不能复用
lst = [1,2,3,4,5,6,7,8,9,0]
it = iter(lst)
print(next(it))
print(next(it))
for e in it:
print(f'for: ', e)1
2
for: 3
for: 4
for: 5
for: 6
for: 7
for: 8
for: 9
for: 0💡可迭代对象和迭代器的区别:
| 特性 | 可迭代对象 | 迭代器 |
|---|---|---|
| 定义 | 实现__iter__()方法的对象 |
实现__iter__()和__next__()方法的对象 |
| 功能 | 可以被迭代 | 可记住迭代状态并产生下一个值 |
| 内存使用 | 更多 | 惰性计算,节省 |
| 数据消耗 | 可多次迭代 | 只能迭代一次 |
| 例 | 列表,元组,字典,字符串 | 文件对象,生成器 |
8.生成器 (Generator)
简单理解:生成器就是一个迭代器
1.生成器是一个返回迭代器的函数,使用yield关键字,只能用于迭代操作,可以利用它进行惰性计算,调用一个生成器函数,就会返回一个迭代器对象。
2.当生成器中使用yield关键字时,函数的执行将会暂停,并将yield后面的表达式当作当前迭代的值返回。
3.每次调用生成器的next方法或使用for循环进行迭代时,函数会从上次暂停的地方继续执行,再到再次遇到yield关键字,这样,生成器函数可以逐步产生值,不需要一次性计算并返回所有结果。
特点:
- 惰性计算 只在需要时生成值
- 内存高效 不一次性的存储所有数据
- 一次性使用 遍历完成后就不能再次使用
例💡:
def countdown(n):
while n > 0:
#当在生成器函数中使用 yield 语句时,函数的执行将会暂停,并将 yield 后面的表达式作为当前迭代的值返回。
yield n
n = n - 1
# 创建生成器对象
generator = countdown(5)
print(type(generator)) # <class 'generator'> 生成器
# 通过迭代生成器获取值
print(next(generator)) # 输出: 5
print(next(generator)) # 输出: 4
print(next(generator)) # 输出: 3
# 使用 for 循环迭代生成器
for value in generator:
print(value) # 输出: 2 1
print(next(generator)) #❌ StopIteration⚠️ 元组推导式只能得到生成器tup而不是元组tup,生成器误传进iter()进行迭代,返回的还是生成器tup本身
lst = [1,2,3,4,5,6,7,8,9,0]
tup = (s*10 for s in lst if s % 2 == 0)
it1 = iter(tup)
it2 = iter(tup)
print(id(tup))
print(id(it1))
print(id(it2))1970972283424
1970972283424
1970972283424生成器迭代后,不能再用tuple()生成元组
lst = [1,2,3,4,5,6,7,8,9,0]
tup = (s*10 for s in lst if s % 2 == 0)
print('迭代前', tuple(tup)) # 迭代前 (20, 40, 60, 80, 0)
for i in tup:
print( f'for- ',i )
print('迭代后', tuple(tup)) # 迭代后 ()💡生成器与推导式的区别:
| 特性 | 推导式 | 生成器 |
|---|---|---|
| 内存使用 | 立即计算,存储所有元素在内存 | 惰性运算,不占用内存存储元素 |
| 返回类型 | 返回集合,列表等具体类型,元组除外 | 生成器对象 |
| 执行时机 | 立即执行,返回所有结果 | 按需,next()时 |
| 重用性 | 可多次使用 | 一次性,遍历后要重新构建 |
| 语法 | [] {}等明确符号和 in for if组成表达式 |
带yield函数 |
| 场景 | 数据量不大,需要立即得到结果 | 大量数据,内存敏感,只需遍历一次 |
内存占用对比:
生成器对象比推导式得到的具体数据结构对象节省内存的多
import sys
COUNT = 10000
large_list = [x for x in range(100 * COUNT)]
print("列表内存占用:", sys.getsizeof(large_list), "bytes") # 8448728 bytes
large_tup = (x for x in range(100 * COUNT))
print("生成器内存占用:", sys.getsizeof(large_tup), "bytes") # 192 bytes执行时机对比:
推导式,整个计算,得到新的列表对象,立即执行,容易瞬间打满CPU/内存
def expensive_operation(x):
print(f"计算 {x} 的平方...")
return x * x
squares_list = [expensive_operation(x) for x in range(10)]
print(squares_list)计算 0 的平方...
计算 1 的平方...
计算 2 的平方...
计算 3 的平方...
计算 4 的平方...
计算 5 的平方...
计算 6 的平方...
计算 7 的平方...
计算 8 的平方...
计算 9 的平方...
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]生成器对象,数据结构并没有实际生成每个成员,只有迭代时用到才产生,惰性执行
squares_gen = (expensive_operation(x) for x in range(10))
print('生成器对象初始化完成')
print(next(squares_gen))
print(next(squares_gen))
print(next(squares_gen))
for result in squares_gen:
print("for -----> ", result)生成器对象初始化完成
计算 0 的平方...
0
计算 1 的平方...
1
计算 2 的平方...
4
计算 3 的平方...
for -----> 9
计算 4 的平方...
for -----> 16
计算 5 的平方...
for -----> 25
计算 6 的平方...
for -----> 36
计算 7 的平方...
for -----> 49
计算 8 的平方...
for -----> 64
计算 9 的平方...
for -----> 81在需要高性能程序时,需要考虑使用生成器优化程序
"如果文章对您有帮助,可以请作者喝杯咖啡吗?"
微信支付
支付宝