Python中的yield用法是一个比较高级的话题,它可以让一个函数变成一个生成器,也就是一个可以按需产生值的可迭代对象。使用yield的函数不再是一个普通的函数,而是在每次调用时返回一个新的值,同时保留上一次的状态。这样可以实现一些高效的功能,比如惰性求值、协程、并发等。 一个最简单的例子,使用yield生成一个斐波那契数列: # 定义一个生成器函数def fib(n): a, b = 0, 1 # 初始化两个变量 while a < n: # 循环条件 yield a # 返回当前值,并暂停执行 a, b = b, a + b # 更新两个变量# 调用生成器函数,返回一个生成器对象g = fib(10)print(g) # <generator object fib at 0x0000020C2E4E5F90># 使用for循环遍历生成器对象for x in g: print(x) # 依次输出0, 1, 1, 2, 3, 5, 8# 使用next()函数获取生成器对象的下一个值g = fib(10) # 重新创建一个生成器对象print(next(g)) # 0print(next(g)) # 1print(next(g)) # 1 从上面的例子可以看出,使用yield的函数在每次调用时都会返回一个新的值,并且记住上一次的状态。这样就可以避免使用列表或其他数据结构来存储中间结果,节省了内存空间。而且,生成器对象是惰性求值的,也就是说只有在需要时才会计算下一个值,提高了执行效率。 其次,来看一下如何使用生成器对象的其他方法,比如send()和throw()。这两个方法可以从外部向生成器内部传递数据或异常,从而改变生成器的行为。例如:
从上面的例子可以看出,使用send()方法可以向生成器内部传递数据,并赋值给yield前面的变量。这样就可以实现一种双向通信,让外部和生成器之间互相影响。使用throw()方法可以向生成器内部抛出异常,并触发相应的处理逻辑。使用close()方法可以关闭生成器,并释放相关资源。 最后,来看一下如何使用yield实现协程和并发。协程是一种轻量级的线程,它可以在多个任务之间切换执行,而不需要操作系统的干预。并发是一种编程模式,它可以让多个任务同时进行,提高程序的运行效率。例如: import time# 定义一个协程函数def task(name): print(f'{name} start') yield # 暂停执行,等待切换 print(f'{name} resume') yield # 暂停执行,等待切换 print(f'{name} end')# 创建两个协程对象t1 = task('Task1')t2 = task('Task2')# 依次执行两个协程对象的第一部分next(t1) # Task1 startnext(t2) # Task2 start# 依次执行两个协程对象的第二部分next(t1) # Task1 resumenext(t2) # Task2 resume# 依次执行两个协程对象的第三部分next(t1) # Task1 endnext(t2) # Task2 end# 定义一个并发函数def concurrent_task(name, n): for i in range(n): print(f'{name}: {i}') yield # 暂停执行,等待切换# 创建两个并发任务c1 = concurrent_task('TaskA', 5)c2 = concurrent_task('TaskB', 5)# 使用循环交替执行两个并发任务,直到完成while True: try: next(c1) next(c2) time.sleep(0.5) # 模拟延迟 except StopIteration: break# Output:# TaskA: 0# TaskB: 0# TaskA: 1# TaskB: 1# TaskA: 2# TaskB: 2# TaskA: 3# TaskB: 3# TaskA: 4# TaskB: 4 从上面的例子可以看出,使用yield可以实现协程和并发的功能,让多个任务可以在同一个线程中交替执行,提高程序的响应速度和资源利用率。 总之,Python中的yield用法是一个非常强大和灵活的特性,它可以让一个函数变成一个生成器,也就是一个可以按需产生值的可迭代对象。使用yield的函数不再是一个普通的函数,而是在每次调用时返回一个新的值,同时保留上一次的状态。这样可以实现一些高效的功能,比如惰性求值、协程、并发等。 |
|