当说起Python里面的高级特性时,就不能不提迭代器(Iterators)和生成器(Generators)啦!它们就像是处理数据的一把利器,特别是对付大数据的时候,简直就是神器!咱们今天就来聊聊它们到底是啥,怎么用,还有点啥实际用途吧!
目录
1. 迭代器(Iterators)
2. 使用迭代器
3. 自定义迭代器
4. 生成器(Generators)
5. 生成器 vs. 列表推导式
6. 生成器的惰性计算(Lazy Evaluation)
7. 生成器的状态管理
8. 生成器的并发与异步
总结
1. 迭代器(Iterators)
什么是迭代器?
迭代Python 最强大的功能之一,而迭代器(Iterators)是一种用于遍历集合的对象。它能记住遍历的位置,并提供一个方法来访问集合中的下一个元素。有两个特点:
- 只能向前遍历,不能后退。
- 使用
for
循环或next()
函数进行遍历。
迭代器的工作原理:
迭代器的工作原理是实现迭代器协议。该协议定义了两个方法:
iter()
: 返回一个新的迭代器对象。next()
: 返回迭代器中的下一个元素。
当迭代器到达集合的末尾时,next()
方法会抛出 StopIteration
异常。
以下是一些可迭代对象的示例:
- 列表
- 元组
- 字符串
- 字典
- 集合
2. 使用迭代器
下面通过两个例子讲一下迭代器。
示例1:使用 for
循环来遍历迭代器。
my_list = [1, 2, 3, 4, 5] #这里的集合是一个列表# 使用 for 循环遍历列表
for item in my_list:print(item)
该代码使用 while True 循环来遍历迭代器。在循环体内,它使用 next() 方法获取迭代器的下一个元素。如果迭代器中没有更多元素,则 next() 方法会引发 StopIteration 异常。
最后,该代码使用 except 语句来处理 StopIteration 异常。当 StopIteration 异常被引发时,该代码会跳出循环。
输入:
1
2
3
4
5
示例2:使用 next()
方法手动遍历迭代器。
# 使用 iter() 函数将列表转换为迭代器。
my_iterator = iter(my_list)# 使用 next() 方法手动遍历列表
while True:try:item = next(my_iterator)print(item)except StopIteration:break
输出:
1
2
3
4
5
3. 自定义迭代器
前面我们使用用 iter() 函数将列表转换为迭代器。当然,也可以创建自定义迭代器来遍历任何类型的数据集。例如,可以创建一个迭代器来遍历一个字符串:
class MyStringIterator:def __init__(self, string):# 将字符串存储为属性self.string = string# 将索引初始化为 0self.index = 0def __iter__(self):# 返回自身以指示它是迭代器return selfdef __next__(self):# 检查是否已到达字符串末尾if self.index < len(self.string):# 获取当前索引处的字符item = self.string[self.index]# 将索引增加 1 以指向下一个字符self.index += 1# 返回字符return itemelse:# 引发 StopIteration 异常以指示迭代结束raise StopIterationmy_string = "Hello, world!"# 使用自定义迭代器遍历字符串
for item in MyStringIterator(my_string):print(item)
输出:
H
e
l
l
o
,w
o
r
l
d
!
关于迭代器,需要记住所有迭代器都是可迭代对象,但并非所有可迭代对象都是迭代器。例如,字符串是可迭代对象,但不是迭代器。
4. 生成器(Generators)
生成器是什么?
生成器(Generators)是一种特殊的迭代器,通过yield
关键字来创建,它可以延迟执行,并逐个生成值。
使用生成器表达式:
# 生成器表达式
my_generator = (x for x in range(10))# 遍历生成器
for item in my_generator:print(item)
输出:
0
1
2
3
4
5
6
7
8
9
使用 yield 关键字创建生成器函数
# 生成器函数
def my_generator():for x in range(10):yield x# 遍历生成器
for item in my_generator():print(item)
输出:
0 1 2 3 4 5 6 7 8 9
5. 生成器 vs. 列表推导式
特性 | 生成器 | 列表推导式 |
---|---|---|
返回数据类型 | 生成器 | 列表 |
内存占用 | 较少 | 较多 |
计算方式 | 惰性计算 | 立即计算 |
适用场景 | 数据量较大、需要多次迭代 | 数据量较小、不需要多次迭代 |
详细说明:
生成器
- 生成器是一个返回迭代器的函数,只能用于迭代操作。
- 生成器对象具有惰性求值的特点,即只有需要的时候才生成元素。
- 可以通过内置函数
next()
或生成器对象的__next__()
方法获取下一个值。
列表推导式
- 列表推导式是一种用来创建列表的语法糖。
- 列表推导式会立即计算并生成整个列表。
- 列表推导式的语法与生成器表达式相似,但返回的是列表而不是生成器。
选择建议:
- 如果要多次迭代,建议使用列表推导式。
- 如果数组很大或者有无穷个元素,建议使用生成器表达式。
6. 生成器的惰性计算(Lazy Evaluation)
惰性计算的优点
- 节省内存:只生成需要的值,不会占用额外的内存空间。
- 提高效率:避免了生成不必要的值,提高了计算效率。
生成器表达式的惰性特性
生成器表达式具有惰性特性,即只在需要时才计算值。例如:
# 生成 1 到 10 的平方数
my_generator = (x**2 for x in range(1, 11))# 仅获取前三个平方数
for item in my_generator:print(item)if item >= 9:break
逐步获取生成器的值
可以使用 next()
方法逐步获取生成器的值:
my_generator = (x**2 for x in range(1, 11))# 逐步获取生成器的值
while True:try:item = next(my_generator)print(item)except StopIteration:break
输出:
1
4
9
16
25
36
49
64
81
100
7. 生成器的状态管理
send() 方法:使用 send()
方法向生成器发送值。
def my_generator():x = 0while True:x = yield xprint("Received:", x)# 使用 send() 方法向生成器发送值
my_generator = my_generator()
next(my_generator) # 初始化生成器
my_generator.send(10)
my_generator.send(20)
输出如下:
Received: 10
Received: 20
throw() 方法:使用 throw()
方法向生成器抛出异常。
def my_generator():try:while True:yieldexcept Exception as e:print("Error:", e)# 使用 throw() 方法向生成器抛出异常
my_generator = my_generator()
next(my_generator)
my_generator.throw(ValueError("Error "))
输出:
Error
close() 方法:使用 close()
方法关闭生成器。
def my_generator():try:while True:yieldfinally:print("Generator closed")# 使用 close() 方法关闭生成器
my_generator = my_generator()
next(my_generator)
my_generator.close() # 输出:Generator closed
8. 生成器的并发与异步
生成器是一个可以暂停和恢复执行的函数,它会生成一个值并暂停,然后等待下一次调用时再继续执行。这使得它们非常适合处理大量的数据或在异步编程中执行并发操作。
使用生成器实现并发
生成器可以与线程一起使用,从而实现一些形式的并发操作。Python 的 concurrent.futures
模块提供了 ThreadPoolExecutor
和 ProcessPoolExecutor
,这些可以与生成器一起使用,允许你并发地运行多个生成器函数。
import concurrent.futuresdef my_generator_function(data):for item in data:# 执行一些操作yield processed_itemdef main():data = [1, 2, 3, 4, 5]with concurrent.futures.ThreadPoolExecutor() as executor:results = list(executor.map(my_generator_function, data))print(results)if __name__ == "__main__":main()
这里的 executor.map
函数允许你并发地调用 my_generator_function
函数,并且结果会被收集到一个列表中。
异步生成器和 async/await
异步生成器允许你在生成器函数中使用 await
关键字,这使得你可以等待其他异步操作完成,而不会阻塞整个生成器。
在 Python 3.6 及更高版本中,你可以使用 async def
定义异步生成器函数,使用 yield
语句生成值:
async def async_generator_function(data):for item in data:# 进行一些异步操作yield processed_item
然后你可以使用 async for
循环来遍历异步生成器产生的值:
async def main():async for item in async_generator_function(data):print(item)if __name__ == "__main__":import asynciodata = [1, 2, 3, 4, 5]asyncio.run(main())
这里的 async for
循环允许你在异步函数中迭代异步生成器的值,而不会阻塞事件循环。
总结
关于迭代器和生成器,这里也讲得差不多了,想必大家对迭代器和生成器的概念也有更深入的理解了。那么,大家可以试试敲敲代码,实际运行一番。
欢迎大家和我一起继续学习、记录python的下一个知识点。
如果感觉阅读对您还有些作用,可以评论留言,关注我。谢谢您的阅读!
往期学习:
Python安装教程(版本3.8.10)windows10
Linux系统:安装Conda(miniconda)
Conda快速安装的解决方法(Mamba安装)
VSCode安装教程(版本:1.87.0)Windows10
Python基础语法:从入门到精通的必备指南
Python的基本数据类型
Python数据类型间的转换(隐式、显式)
Python基础知识:运算符详解
Python基础知识:数字类型及数学函数详解-
Python字符串操作及方法详解!一篇就搞定!
Python列表及其操作详解,从此不再迷茫!
Python元组(Tuple)深度解析!
Python字典的使用技巧(一篇详解)
Python条件控制深度解析,成为编程必备
Python循环语句全解析(附实战演练)
Python函数高效编程技巧,提升你的代码效率!
Python模块和包全解析,一篇文章就够!
Python lambda(匿名函数),一文详解
Python面向对象编程:合集篇(类、对象、封装、继承和多态)
Python命名空间和作用域,让你的代码逻辑更清晰!
Python正则表达式初学者指南,轻松上手!