一 .   生成器

1.介绍

通过列表生成式,可以直接创建一个列表,但是受内存限制,列表容量是有限的。 

 a = [i*2 for i in range(10000)

 print (a)


如果列表元素可以按照某种算法推算出来,是否可以在循环的过程中不断推算出后续的元素?
这样就不必创建完整的list,从而俭省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器,generator.
a = (i*2 for i in range(10000))
for i in a:
print (i)

generator比较强大,但是如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

比如:斐波那契数列,除了第一个和第二个数之外,任意的数都可有前面两个数相加得到(1,1,2,3,5,8,......)
 1 def fib(max):
 2     n, a, b = 0, 0, 1
 3     while n < max:   #n只是控制循环
 4         print(b)
 5         a, b = b, a + b
 6 
 7         # 相当于:t = (b, a + b)  (t是一个元组)
 8         #          a = t[0]
 9         #          b = t[1]
10         #不等价于下面的
11         #a = b   a = 1,b = 2,a = b, a = 2
12         #b = a +b ,b = 2 + 2 = 4
13 
14         n=n+1
15     return 'done'
16 fib(100)  #生成100斐波那契数
View Code

 1 def fib(max):
 2     n, a, b = 0, 0, 1
 3     while n < max:   #n只是控制循环
 4         #print(b)
 5         yield b      #就变成生成器了
 6         a, b = b, a + b
 7 
 8         # 相当于:t = (b, a + b)  (t是一个元组)
 9         #          a = t[0]
10         #          b = t[1]
11         #不等价于下面的
12         #a = b   a = 1,b = 2,a = b, a = 2
13         #b = a +b ,b = 2 + 2 = 4
14 
15         n=n+1
16     return 'done'  #异常的时候打印的一个信息
17 f = fib(10)  #生成100斐波那契数
18 print(f.__next__())
19 print(f.__next__())
20 print("_________")   #函数想停就停,随意进出
21 print(f.__next__())
22 print(f.__next__())
23 print(f.__next__())
24 print("=====star loop======")
25 for i in f:
26     print(i)
View Code

补充:

异常捕捉;

还可以通过yield 实现在单线程的情况下实现并发运算的效果。

 

 

 1 import time
 2 def consumer(name):       #消费者
 3     print("%s 准备吃包子啦!" %name)
 4     while True:
 5        baozi = yield
 6 
 7        print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
 8 
 9 c = consumer("xiaolai")
10 c.__next__()    #只是为了打印print("%s 准备吃包子啦!" %name)
11 
12 def producer(name):      #生产者
13     c = consumer('A')
14     c2 = consumer('B')
15     c.__next__()
16     c2.__next__()    #唤醒yield
17     print("老子开始准备做包子啦!")
18     for i in range(10):
19         time.sleep(1)
20         print("做了1个包子,分两半!")
21         c.send(i)
22         c2.send(i)   #唤醒yield并且传值
23 
24 producer("shogou")

 

 

2.说明:

     生成器,只有在调用时才会生成相应的数据。(只能用循环,不能像列表一样去切片))

    只记住当前位置;

    只有一个  .__next__方法。  (2.X版本中next())

 

 

二. 迭代器

      可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型:list , tuple ,dict ,set ,str等;

一类是generator,包括生成器和带yield的generator function.

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable.

可以使用isinstance() 判断一个对象是否是Iterable对象

>>>from collections import Iterable
>>>isinstance([], Iterable)
True

生成器不但可以作用于for循环,还可以被__next__()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

可以被__next__()函数调用并不断返回下一个值的对象称为迭代器:Iterator.(是迭代器就有__next__()方法)

 

>>>from collections import Iterator
>>>isinstance([], Iterator )
False

 

生成器都是Iterator对象,但list, dict ,str 虽然是Iterable,却不是Iterator。把list, dict ,str 等Iterable变成Iterator可以使用iter()函数:

 a=[1,2,3]

type (a)
b = iter(a)
b.__next__()

小结:

      Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算,Iterator甚至可以表示一个无限大的数据流,例如全体自然数。使用list是永远不可能存储全体自然数的 。