python(迭代器,生成器)

Posted shine-rainbow

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python(迭代器,生成器)相关的知识,希望对你有一定的参考价值。

1.迭代

  将某个数据集中的数据‘一个一个挨着取出来’,就是迭代。

1 ‘‘‘
2 dir([1,2].__iter__())是列表迭代器中实现的所有方法,dir([1,2])是列表中实现的所有方法,都是以列表的形式返回给我们的,为了看的更清楚,我们分别把他们转换成集合,
3 然后取差集。
4 ‘‘‘
5 #print(dir([1,2].__iter__()))
6 #print(dir([1,2]))
7 print(set(dir([1,2].__iter__()))-set(dir([1,2])))

 运行结果:{‘__length_hint__‘, ‘__setstate__‘, ‘__next__‘}

 其中 __length_hint__表示的是迭代元素的个数。

 __next()__表示取出元素

 __setstate__设置迭代起始的位置

 1 iter_l = [1,2,3,4,5,6].__iter__()
 2 # 获取迭代器中元素的长度
 3 print(iter_l.__length_hint__())
 4 # 根据索引值指定从哪里开始迭代
 5 print(*,iter_l.__setstate__(4))
 6 #一个一个的取值
 7 print(**,iter_l.__next__())
 8 print(***,iter_l.__next__())
 9 # 如果再次__next__()会直接报错
10 print(****,iter_l.__next__())
11 # 报错 停止迭代 StopIteration

使用try except处理这个异常

1 # 使用异常处理机制处理这个机制
2 list_1 = [1,2,3,4,5,6]
3 iterator = list_1.__iter__()
4 while 1:
5     try:
6         item = iterator.__next__()
7         print(item)
8     except StopIteration:
9         break

迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法

对range()进行如下测试:

1 print(__iter__ in dir(range(12))) # True
2 print(__next__ in dir(range(12))) # False
3 from collections import Iterator
4 from collections import Iterable
5 print(isinstance(range(2),Iterator)) # False 不是一个迭代器 迭代器必须同时满足__iter__ __next__
6 print(isinstance(range(2),Iterable)) # True 是一个迭代对象 __iter__ 

可迭代协议 

 可以被迭代的满足的要求就叫做可迭代协议。可迭代协议的定义非常的简单。就是在内部实现了__iter__方法。

 分析__iter__方法做了什么事情呢?

1 print([1,2,3].__iter__()) # <list_iterator object at 0x10ae1a2e8>
2 print(range(2).__iter__()) # <range_iterator object at 0x10aeef6f0>

随后就可以快乐的使用for in i xxx 就可以迭代取出内部的数据咯

1 i = range(2).__iter__() # <range_iterator object at 0x10aeef6f0>
2 for j in i:
3     print(j) # 0 i

2.生成器

  2.1 生成器函数

  一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

 1 def generator():
 2     print(1)
 3     yield a
 4     print(2)
 5     yield b
 6 g = generator()
 7 # print(g) # <generator object generator at 0x110419f10>
 8 # print(g.__next__())
 9 """
10 1
11 a
12 """
13 # print(g.__next__())
14 """
15 1
16 a
17 2
18 b
19 """
20 # print(g.__next__()) # 没有了报错。.StopIteration
21 # 当前 使用for 迭代取出
22 for i in g:
23     print(i)
24 """
25 1
26 a
27 2
28 b
29 """

生成器有什么好处呢?就是不会一下子在内存中生成太多数据。

假设要生产200w箱娃哈哈. 按需生产。请求一箱。生产一箱。

 1 # 200w箱娃哈哈 需要一箱。生产一箱
 2 import time
 3 def create_wahaha():
 4     for i in range(1,2000000):
 5         yield生产了%s箱娃哈哈%i
 6 
 7 generator = create_wahaha()
 8 # 开始要第一箱娃哈哈
 9 for i in range(100):
10     if i == 10:
11         break
12     print(generator.__next__())
13     time.sleep(1)
14 
15 
16 print(generator.__next__()) # 生产了11箱娃哈哈 并不会从第一箱开始.除非再次调用create_wahaha()
17 
18 
19 generator2 = create_wahaha()
20 print(generator2.__next__()) # 生产了1箱娃哈哈

 2.2、send

技术分享图片
 1 def generator():
 2     print(123)
 3     content = yield 1
 4     print(=====,content)
 5     print(456)
 6     yield 2
 7 g = generator()
 8 ret = g.__next__()
 9 print("*****",ret) 
10 ret = g.send(hello)
11 print(*******,ret)
12 """
13 123
14 ***** 1
15 ===== hello
16 456
17 ******* 2
18 """
19 # 使用send获取下一个值的效果和next基本一致
20 # 只是在获取下一个值的时候,给上一个yield的位置传递一个数据
21 # --------
22 # 第一次使用生成器的时候,必须使用next获取下一个值
23 # 最后一个yield不能接收外部的值
send

小试牛刀,借助yield计算移动的平均速度

技术分享图片
 1 def average():
 2     total = 0
 3     count = 0
 4     avg = None
 5     while True:
 6       term = yield avg
 7       total += term
 8       count +=1
 9       avg = total / count
10 a = average()
11 # next(a)
12 a.__next__()
13 print(a.send(10))
14 print(a.send(20))
15 print(a.send(30))
使用send计算平均速度

进一步借助装饰器去掉每一次调用必须执行next()

技术分享图片
 1 def init(func): #在调用被装饰生成器函数的时候首先用next激活生成器
 2     def inner(*agrs,**kwargs):
 3         g = func(*agrs,**kwargs)
 4         next(g)
 5         return g
 6     return inner
 7 
 8 @init
 9 def average():
10     total = 0.0
11     count = 0
12     average = None
13     while True:
14         term = yield average
15         total += term
16         count += 1
17         average = total / count
18 g_avg = average()
19 # next(g_avg) 在装饰器中已经执行了该方法
20 print(g_avg.send(10))
21 print(g_avg.send(20))
带装饰器简化send

 

以上是关于python(迭代器,生成器)的主要内容,如果未能解决你的问题,请参考以下文章

python:可迭代对象,迭代器,生成器函数,生成器的解析举例代码说明

Python概念之装饰器迭代器生成器

python函数:迭代器和生成器

Python3 迭代器与生成器

Python的高级特性(切片,迭代,生成器,迭代器)

Python---迭代器,生成器,列表推导式