迭代器
迭代器时一个可以记住遍历位置的对象
迭代器对象 从第一个元素开始访问,直到所有元素被访问完结束
迭代器只能前进,不能后退
可迭代对象
实现了
__iter__()
方法的对象或者实现了可以返回一个迭代器的
__getitem__()
方法(支持下标索引)
每迭代一次,都会返回对象中的下一个元素
一直向后读取,知道迭代了所有的数据
# 列表是一个可迭代对象
my_list = [1, 2, 3]
# 使用 for 循环遍历可迭代对象
for item in my_list:
print(item)
# 使用 iter() 函数获取迭代器
my_list_iter = iter(my_list)
print(my_list_iter) # 输出 <list_iterator object at 0x...>
迭代器
实现了
__iter__()
和__next__()
方法的对象
__iter__()
返回迭代器自身,而__next__()
返回序列中的下一个值如果没有值可返回,则会引发
StopIteration
异常
# 通过 iter() 函数获取迭代器
my_list_iter = iter(my_list)
# 使用 next() 函数获取下一个元素
print(next(my_list_iter)) # 输出 1
print(next(my_list_iter)) # 输出 2
print(next(my_list_iter)) # 输出 3
# 如果继续调用 next(),会引发 StopIteration 异常
try:
print(next(my_list_iter))
except StopIteration:
print("End of iterator")
自定义迭代器
可迭代对象的 迭代器一旦被完全消费,状态不会重置
每次需要重新迭代时,可以创建新的迭代器实例,或实现返回新迭代器实例的
__iter__
方法
class MyIterator:
def __init__(self, data):
print("Initializing MyIterator")
self.data = data
self.index = 0
def __iter__(self):
print("Calling __iter__")
return self
def __next__(self):
print("Calling __next__")
if self.index < len(self.data):
result = self.data[self.index]
self.index += 1
return result
raise StopIteration
# 创建可迭代对象和迭代器
test_list = [1, 2, 3, 4]
my_iterable = MyIterator(test_list)
# 初始化完成,打印类型
print(type(test_list)) # <class 'list'>
print(type(my_iterable)) # <class '__main__.MyIterator'>
# 使用 for 循环遍历
for item in my_iterable:
print("Iterating item:", item)
# TODO:再次使用for循环,就不执行了
for item in my_iterable:
print("Inerating angin", item)
##################
# 使用 for 循环遍历
for item in MyIterator(test_list):
print(item)
# 再次创建新的迭代器实例
for item in MyIterator(test_list):
print(item)
区别和联系
可迭代对象:可以用
iter()
函数获取迭代器的对象。常见的内置类型如列表、元组、字符串等都是可迭代对象。迭代器:实现了
__iter__()
和__next__()
方法的对象。迭代器本身也是可迭代对象,因为它实现了__iter__()
方法并返回自身。
常用的内置函数和方法
iter(obj)
:获取对象的迭代器。next(iterator[, default])
:获取迭代器的下一个元素,如果迭代结束则返回默认值(如果提供)。list()和tuple()
中也可以传递可迭代对象
for循环的本质
先吊用
iter()
函数,它会自动调用可迭代对象中的__iter__
方法,返回这个可迭代对象的 迭代器对获取到的迭代器 不断调用
next()
函数,它会自动调用迭代器中的__next__
方法来获取下一个值但遇到
StopInteration
异常后,循环结束
生成器
生成器(Generator)是 Python 中的一种用于创建迭代器的简便方式,是一类特殊的迭代器
让你在迭代过程中产生值,而不需要一次性将所有值加载到内存中,大量数据或流式数据时特别有用(惰性求值)
基本概念
生成器函数:使用
yield
关键字的函数,这个函数在调用时返回一个生成器对象。生成器表达式:类似于列表推导式,但使用小括号而不是方括号,返回一个生成器对象。
特点
惰性求值:生成器按需生成值,可以节省内存。
状态记忆:生成器在每次产生值后会记住其状态,下一次迭代会从上次停止的地方继续。
生成器函数
使用 yield
关键字的函数会返回一个生成器对象
每次调用生成器的 __next__()
方法时,生成器函数会运行到下一个 yield
语句,返回相应的值,并暂停执行,保存当前的执行状态。
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
# 使用生成器函数
fib = fibonacci(10)
for num in fib:
print(num)
生成器表达式
生成器表达式使用类似列表推导式的语法,但用小括号包裹
它们返回一个生成器对象,可以像迭代器一样使用
# 创建一个生成器表达式,生成从0到9的平方数
squares = (x * x for x in range(10))
# 使用生成器
for square in squares:
print(square)
send、next的区别
在启动生成器时,第一个方法调用必须是
next
或send(None)
,因为在生成器启动时没有yield
语句可以接收值。
功能不同:
next
方法:恢复生成器执行到下一个yield
语句,并返回该yield
语句的值。send
方法:向生成器发送一个值,并恢复生成器执行到下一个yield
语句。发送的值成为上一个yield
表达式的返回值。
启动生成器:
next
方法:可以用来启动生成器。send
方法:必须以send(None)
的形式来启动生成器。
用法场景:
next
方法:用于简单的值生成和迭代。send
方法:用于需要向生成器内部传递数据的复杂交互。
def interactive_generator():
print('Generator started')
value = yield 1
print(f'Received: {value}')
value = yield 2
print(f'Received: {value}')
value = yield 3
print(f'Received: {value}')
gen = interactive_generator()
# 启动生成器,必须使用 next 或 send(None)
print(next(gen)) # Generator started, 输出: 1
# 使用 send 向生成器发送数据,并继续执行到下一个 yield
print(gen.send('first')) # Received: first, 输出: 2
print(gen.send('second')) # Received: second, 输出: 3
# 生成器到此结束,再调用会引发 StopIteration 异常
# print(next(gen)) # 会引发 StopIteration 异常
高级用法
斐波那契数列
斐波那契数列:
# 返回列表
def fib_list(n):
if n == 1:
return [1]
if n == 2:
return [1, 1]
fibs = [1, 1]
for i in range(2, n):
fibs.append(fibs[-1] + fibs[-2])
return fibs
# yield实现
def fib_yield(n):
if n == 1:
yield 1
if n == 2:
yield 1
yield 1
fibs = [1, 1]
for i in range(2, n):
fibs.append(fibs[-1] + fibs[-2])
yield fibs[-1]
# 递归实现
def fib_recursion(n):
if n == 1 or n == 2:
return 1
return fib_recursion(n - 1) + fib_recursion(n - 2)
# 返回单个值
def fib(n):
if n == 1 or n == 2:
return 1
return fib(n - 1) + fib(n - 2)
print(fib_list(10))
无限序列
生成器可以用于生成无限序列,只在需要时产生值。
def count(start=0, step=1):
n = start
while True:
yield n
n += step
# 使用无限生成器
counter = count(10, 2)
for _ in range(5):
print(next(counter))
管道模式
生成器可以通过管道模式连接,用于数据流的逐步处理。
def integers():
for i in range(1, 9):
yield i
def squared(seq):
for i in seq:
yield i * i
def negated(seq):
for i in seq:
yield -i
# 使用管道模式
numbers = integers()
squared_numbers = squared(numbers)
negated_numbers = negated(squared_numbers)
for num in negated_numbers:
print(num)
yield from
yield from
可以用于委托部分生成工作给另一个生成器。
def generator_a():
yield 1
yield 2
def generator_b():
yield from generator_a()
yield 3
yield 4
# 使用生成器
for num in generator_b():
print(num)
总结
生成器函数:使用
yield
关键字定义,生成器函数每次暂停在yield
语句处,返回值并保存状态生成器表达式:类似列表推导式,使用小括号,返回生成器对象
优点:生成器惰性求值,节省内存,可以处理无限序列和管道数据流
高级用法:无限序列、管道模式、`yield from` 用于简化生成器代码
生成器是 Python 中处理大量数据和流式数据的强大工具,通过按需生成值来优化性能和内存使用
yield拓展
yield
与协程(coroutines)有密切关系
协程是一种更为复杂和灵活的生成器,用于实现多任务协作和异步编程
Python 中,yield
和 yield from
可以用来创建简单的协程
yield
和 协程
生成器(Generators):
生成器是使用
yield
关键字定义的函数,它们每次调用时生成一个值并暂停执行,保留当前的执行状态生成器是协程的基础
协程(Coroutines)
协程是可以在执行过程中暂停并恢复的函数,允许在暂停点进行数据传输
协程的一个显著特点是可以通过
yield
表达式接收外部发送的数据。
基本生成器示例
def simple_generator():
yield 1
yield 2
yield 3
gen = simple_generator()
print(next(gen)) # 输出: 1
print(next(gen)) # 输出: 2
print(next(gen)) # 输出: 3
协程示例
协程不仅可以产出值,还可以接收值。下面是一个简单的协程示例:
def simple_coroutine():
print('Coroutine started')
x = yield
print(f'Coroutine received: {x}')
coro = simple_coroutine()
print(next(coro)) # 启动协程,输出: Coroutine started
print(coro.send(42)) # 向协程发送数据,输出: Coroutine received: 42
在这个示例中,yield
表达式不仅可以返回值,还可以通过 send
方法接收值
这个特性使协程能够在不同执行点之间交换数据。
yield from
和 子生成器
yield from
可以简化协程代码,使得一个生成器可以委派其部分操作给另一个生成器。
def generator_a():
yield 1
yield 2
def generator_b():
yield from generator_a()
yield 3
yield 4
for value in generator_b():
print(value) # 输出: 1, 2, 3, 4
async/await
在 Python 3.5 引入了 async
和 await
关键字,用于创建和管理协程
这些关键字使得编写异步代码更加直观和强大
import asyncio
async def async_coroutine():
print('Coroutine started')
await asyncio.sleep(1)
print('Coroutine ended')
# 运行协程
asyncio.run(async_coroutine())
yield
与 async/await
的对比
yield
:用于生成器和协程,适用于简单的协作多任务和数据流操作async/await
:用于现代协程,适用于异步编程和并发操作
总结
生成器:使用
yield
创建,主要用于逐步生成值协程:使用
yield
和yield from
创建,允许在执行过程中暂停和恢复,可以在暂停点交换数据async/await:用于现代协程,提供更简洁的异步编程语法,适合处理 I/O 绑定和高并发任务
yield
是协程的基础,允许在执行过程中暂停和恢复而
async
和await
提供了更高层次的抽象,简化了异步编程模型
评论区