生成器和迭代器
Posted su-sir
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了生成器和迭代器相关的知识,希望对你有一定的参考价值。
生成器
定义:在Python中一边循环一边计算的机制,称为生成器,生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器,生成器遇到return 会抛出异常,生成器一次只能产生一个值。
创建生成器:
方法1:只要把一个列表生成式的[]中括号改为()小括号,就创建一个generator
# 列表生成式 lis = [x * x for x in range(10)] print(lis) # 生成器 generator_ex = (x * x for x in range(10)) print(generator_ex)
# 两者之间的转换
list
(x
*
*
3
for
x
in
range
(
5
))
结果: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] <generator object <genexpr> at 0x0000028942CF6D48> # 生成器可以使用next()方法来调用 generator_ex = (x for x in range(10)) print(next(generator_ex)) print(next(generator_ex)) print(next(generator_ex)) print(next(generator_ex)) print(next(generator_ex)) print(next(generator_ex)) print(next(generator_ex)) print(next(generator_ex)) print(next(generator_ex)) print(next(generator_ex)) print(next(generator_ex)) 结果: 0 1 2 3 4 5 6 7 8 9 Traceback (most recent call last): File "C:/Users/admin/PycharmProjects/test1/generator.py", line 36, in <module> print(next(generator_ex)) StopIteration Process finished with exit code 1 # 生成器可以使用__next__()方法调用 generator_ts = (x for x in range(10)) print(generator_ts.__next__()) print(generator_ts.__next__()) print(generator_ts.__next__()) print(generator_ts.__next__()) print(generator_ts.__next__()) print(generator_ts.__next__()) print(generator_ts.__next__()) print(generator_ts.__next__()) print(generator_ts.__next__()) print(generator_ts.__next__()) print(generator_ts.__next__()) 结果: 0 1 2 3 4 5 6 7 8 9 Traceback (most recent call last): File "C:/Users/admin/PycharmProjects/test1/generator.py", line 36, in <module> print(generator_ts.__next__()) StopIteration 生成器还可以使用for来调用 generator_fs = (x for x in range(10)) for i in generator_fs: print(i) 结果: 0 1 2 3 4 5 6 7 8 9
注意:当使用next()和__next__()调用生成器时,超出范围就会报错,但使用for就不会,因为for它把异常捕捉了。
方法2:使用yield实现生成器
# 生产斐波那契数列 def fib(max): n,a,b =0,0,1 while n < max: yield b a,b =b,a+b n = n+1 return ‘done‘ g = fib(6) while True: try: x = next(g) # 捕获了异常,也就不会再报错了 print(‘generator: ‘,x) except StopIteration as e: print("生成器返回值:",e.value) break 结果: 0 1 2 3 4 5 6 7 8 9 generator: 1 generator: 1 generator: 2 generator: 3 generator: 5 generator: 8 生成器返回值: done
方法3:可以通过yield实现在单线程的情况下实现并发运算的效果
import time def consumer(name): print("%s 准备学习啦!" %name) while True: lesson = yield # 这点时后面send传值的时候会被lesson接收,此时yield就不起作用了 print("开始[%s]了,[%s]老师来讲课了!" %(lesson,name)) def producer(name): c = consumer(‘A‘) # 创建生成器A c2 = consumer(‘B‘) # 创建生成器B c.__next__() # 调用生成器A,出现阻塞 c2.__next__() # 调用生成器B,出现阻塞 print("同学们开始上课 了!") for i in range(10): # 在阻塞的时候下面就实现了并发 time.sleep(1) print("到了两个同学!") c.send(i) # 激活生成器A c2.send(i) # 激活生成器B 结果: A 准备学习啦! B 准备学习啦! 同学们开始上课 了! 到了两个同学! 开始[0]了,[A]老师来讲课了! 开始[0]了,[B]老师来讲课了! 到了两个同学! 开始[1]了,[A]老师来讲课了! 开始[1]了,[B]老师来讲课了! 到了两个同学! 开始[2]了,[A]老师来讲课了! 开始[2]了,[B]老师来讲课了! 到了两个同学! 开始[3]了,[A]老师来讲课了! 开始[3]了,[B]老师来讲课了! 到了两个同学! 开始[4]了,[A]老师来讲课了! 开始[4]了,[B]老师来讲课了! 到了两个同学! 开始[5]了,[A]老师来讲课了! 开始[5]了,[B]老师来讲课了! 到了两个同学! 开始[6]了,[A]老师来讲课了! 开始[6]了,[B]老师来讲课了! 到了两个同学!
生成器中next()和send()的区别:
其实next()和send()在一定意义上作用是相似的,区别就在于send可传递参数给yield表达式,这时候传递的参数就会作为yield表达式的值,而yield的参数是返回给调用者的值,也就是说send可以强行修改上一个yield表达式值。需要提醒的是,第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有Python yield语句来接收这个值。结合上面的例子:先使用c.__next__(),这样后面send才不会报错,send传的值时被lesson接收了
迭代器
for循环的数据类型有以下几种:
一类是基础容器,如list,tuple,dict,set,str等
一类是generator,包括生成器和带yield的generator function
凡是直接作用于for 循环的对象统称为可迭代对象:Iterable
凡是可作用于next()
函数的对象都是迭代器:Iterator
,它们表示一个惰性计算的序列;
迭代对象和迭代器可以通过iter方法转换
# 判断时迭代对象还是迭代器 from collections.abc import Iterator # 迭代器 from collections.abc import Iterable # 迭代对象 print(isinstance((x for x in range(10)), Iterator)) print(isinstance([],Iterable)) 结果: True True 迭代对象转换为迭代器 list1 = [1,2,3] lst = iter(list1) print(next(lst)) print(next(lst)) print(next(lst)) print(next(lst)) 结果: 1 2 3 Traceback (most recent call last): File "C:/Users/admin/PycharmProjects/test1/generator.py", line 53, in <module> print(next(lst)) StopIteration
迭代器和迭代对象都有__iter__方法,但迭代器有__next__方法,迭代对象却没有
>>> dir([]) # 迭代对象 [‘__add__‘, ‘__class__‘, ‘__contains__‘, ‘__delattr__‘, ‘__delitem__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘,
‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__gt__‘, ‘__hash__‘, ‘__iadd__‘, ‘__imul__‘,
‘__init__‘, ‘__init_subclass__‘, ‘__iter__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__mul__‘, ‘__ne__‘, ‘__new__‘,
‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__reversed__‘, ‘__rmul__‘, ‘__setattr__‘, ‘__setitem__‘, ‘__sizeof__‘,
‘__str__‘, ‘__subclasshook__‘, ‘append‘, ‘clear‘, ‘copy‘, ‘count‘, ‘extend‘, ‘index‘, ‘insert‘, ‘pop‘, ‘remove‘, ‘reverse‘, ‘sort‘] >>> a = iter([]) >>> dir(a) 迭代器 [‘__class__‘, ‘__delattr__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__gt__‘,
‘__hash__‘, ‘__init__‘, ‘__init_subclass__‘, ‘__iter__‘, ‘__le__‘, ‘__length_hint__‘, ‘__lt__‘, ‘__ne__‘, ‘__new__‘,
‘__next__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__setstate__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘]
以上是关于生成器和迭代器的主要内容,如果未能解决你的问题,请参考以下文章