Python迭代器 iterator(iter next) 生成器 generator(yield) yield
迭代器
1、通过iter()方法获得了list的迭代器对象,然后就可以通过next()方法来访问list中的元素了。
当容器中没有可访问的元素后,next()方法将会抛出一个StopIteration异常终止迭代器。
字符串,列表或元组对象都可用于创建迭代器
2、迭代器的限制
不能回到开始
也无法复制一个迭代器。
因此要再次进行迭代只能重新生成一个新的迭代器对象。
3、__iter__() 和 __next__() 方法
__iter__() 和 __next__() 方法这两个方法是迭代器最基本的方法:
一个用来获得迭代器对象
一个用来获取容器中的下一个元素
_list = [5,6,7] it = iter(_list) print(_list) print(it) print(it.__next__()) print(it.__next__()) print(it.__next__()) print(it.__next__()) #此时调用会抛出异常
另一种调用方法
_list = [5,6,7] it = iter(_list) print(_list) print(it) print(next(it)) print(next(it)) print(next(it)) print(next(it)) #此时调用会抛出异常
遍历迭代器
list_ = [5,6,7] it = iter(list_) print(it) for i,v in enumerate(it): print(i,v)
生成器
在一个函数中,只要有yield。那么这个函数就不再是函数,而成了一个生成器
生成器的本质就是迭代器,生成器是一种特殊的迭代器
如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的ist,从而节省大量的内存资源。
在Python中,这种一边循环一边计算的机制,称为生成器(Generator)
生成器的作用:可以实现多任务(协程-->模拟并发)
生成器包括两种:生成器函数和生成器表达式
遍历生成器
①
list(a)
②
for i in a: print(i)
③
for idx,param in enumerate(net.parameters()): print(param)
生成器表达式
将列表解析式[] 改成 () 即可。
g = (x*x for x in range(10)) print(g) print(next(g)) print(next(g)) print(next(g)) print(next(g))
但是生成器不能通过类来实现
生成器函数
生成器函数返回数据就不适用return这个关键字了,是用yield
一个包含yield关键字的函数就是一个生成器函数。(python中yield关键字是区分新老Pythoner的标志之一)
并且yield不能和return共用,并且yield只能用在函数内
yield关键字,其作用和return的功能差不多,就是返回一个值给调用者,只不过有yield的函数返回值后函数依然保持调用yield时的状态,当下次调用的时候,在原先的基础上继续执行代码,直到遇到下一个yield或者满足结束条件结束函数为止
(1)生成器函数执行之后会得到一个生成器作为返回值,并不会执行函数体。
(2)执行了__next__()方法之后才会执行函数体,并且获得返回值。
(3)生成器内部支持了生成器协议,不需要明确定义__iter__() 和 __next__()方法
(3)yield和return相同的是可以返回值,但是不同的是yield 不会结束函数
def test(): yield 1 yield 2 yield 3 t = test() print(next(t))#output:1 print(next(t))#output:1 print(next(t))#output:1 print(next(t))#output:Traceback (most recent call last):StopIteration
好像并没啥卵用啊!骚年,存在即合理,python有生成器不是没有道理的。数学中有很多算法是无限穷举的(比如自然数),我们不可能一一穷举出来,所以生成器就可以帮助我们。
def foo(num): print("starting...") while num<10: num=num+1 yield num for n in foo(0): print(n)
理解yield的作用
def fibonacci(n): a = 0 b = 1 nums = [] for _ in range(n): nums.append(a) a,b = b, a+b return nums for i in fibonacci(10): print(i)
可以写为
def fibonacci(n): a = 0 b = 1 for _ in range(n): yield a a,b = b, a+b for i in fibonacci(10): print(i)
这里的yield表示,每当我们计算出一个元素,就立马将这个元素给送出去。也就是说,外面的for循环就会立即输出这个数。
因此使用yield的好处是,我们并不需要等待整个列表都生成完毕后,再来一个一个的输出。同时也可以节省存储空间。
yield的优势在于一些非常耗时的操作,比如我们可以写一个函数从网络上下载一系列文档,并输出每个文档的内容。如果我们使用yield,则可以保证在一个文档被下载成功后,就立马输出它的内容,而无需等待所有文档都下载完毕。