Python生成器

简单的生成器,生成器解析式:

1 #usr/bin/env python3
2 # -*- codign=utf-8 -*-
3 
4 myGenerator = (x*x for x in range(10)) #简单的生成器
5 print(type(myGenerator)) #输出<class 'generator'>
6 print(dir(myGenerator)); #输出:['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']

dir()发现里面发现有迭代器中的__iter__()和__next__(),这说明myGenerator是迭代器,是迭代器就可以用for循环。

1 #既然有迭代器的属性就可以用next()循环读取
2 print("First number: ", next(myGenerator)) #First number:  0
3 print("Second Number: ", next(myGenerator)) #Second Number:  1
4 
5 #循环读取余下的
6 for i in myGenerator:
7     print(i) #输出1-10的平方的结果

再看熟知的list:

 1 myList = [x*x for x in range(10)]; #定义列表解析式
 2 print(type(myList)) #输出:<class 'list'>
 3 print(dir(myList)) ##['__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']
 4 
 5 #print(next(myList)) #出错:TypeError: 'list' object is not an iterator,说明不可迭代
 6 #第一次循环有输出
 7 for i in myList:
 8     print(i) #有输出
 9 #第二次循环还是有输出
10 for j in myList:
11     print(j) #有输出

总结:

1,生成器在第一次循环的时候,将myGenerator里的值依次读取并打印,再次读取的,就发现没有任何结果了。迭代器所具有的特性。这与列表不同。

2,生成器解析在很多地方都可以替代列表解析,因为,它占用内存少。

3,代码优雅简洁。如下:

1 sum(i*i for i in range(10)) #生成器
2 sum([i*i for i in range(10)]) #列表解析

yield,真正的生成器利器。

 1 def myGenerator():
 2     yield 0
 3     yield 1
 4     yield 2
 5 
 6 myGenerator = myGenerator()
 7 print(myGenerator) #输出:<generator object myGenerator at 0x7fa02fdedac0>
 8 print(type(myGenerator)) #输出:<class 'generator'>
 9 print(dir(myGenerator)) #输出有:__iter__()和__next__()说明是迭代器
10 print(next(myGenerator)) #输出0
11 print(next(myGenerator)) #输出1
12 print(next(myGenerator)) #输出2
13 print(next(myGenerator)) #读取完了,错误提示,发起StopIteration

也就是说,这个含有yeild关键词的函数myGenerator返回值是一个生成器类型的对象。而这个生成器就是迭代器。也可以把含有yeild语句的函数叫做生成器。是一种用普通函数语法定义的迭代器。上例函数解析:

  1. myGenerator = myGenerator()。调用函数并把它赋值给变量myGenerator,除了返回生成器外什么都没有做,任何值都不会返回。
  2. print(myGenerator)。打印一下对象,说明是生成器类型。
  3. print(type(myGenerator))。查看类型。
  4. print(dir(myGenerator))。还是查看。
  5. print(next(myGenerator))。生成器开始执行,遇到第一个yeild语句,将值返回并暂停执行(有的称之为挂起)。
  6. print(next(myGenerator))。再次调用next(),从上次暂停的位置开始,将值返回,并暂停。
  7. print(next(myGenerator))。重复上面操作。
  8. print(next(myGenerator))。重复上面操作。

执行过程:yeild除了作为生成器的标志之外,还有一个功能就是返回值。既然是返回值,那么在函数内部跟return有什么区别?

首先看return:

1 def checkReturn():
2     print "Begin......"
3     while n > 0:
4         print("Before return.")
5         return n
6         n -= 1
7         print("After return.")
8 a = checkReturn(3) #输出了函数体内的第一个和第二个print语句:Begin...... Before return.
9 print(a) #执行函数体内的return n 语句,输出3

上面的代码并没有执行函数体内return语句后面的语句,也就是函数体内遇到return后只执行return语句,return语句后面的代码都不执行。

再看yeild:

 1 def checkYeild(n):
 2     print("Begin to check yield.....")
 3     while n > 0:
 4         print("Before yeild.")
 5         yield n
 6         n -= 1
 7         print("After yeild")
 8 
 9 b = checkYeild(3) #调用函数checkYeild,除了返回生成器什么都不做
10 print("First time to call: ", next(b)) #遇到yeild,返回值,暂停。
11 print("Second time to call: ", next(b))  #从上次暂停位置继续执行
12 print("Third time to call: ", next(b)) #又遇到yeild,返回值,暂停。
13 print("Forth time to call: ", next(b)) #第四次调用的时候,发现n已经不满足条件while n>0了,发起StopIteration

用生成器些斐波那契数列:

 1 def fibs(fmax):
 2     '''
 3     Generator for fibonacci sequence
 4     '''
 5     n, a, b = 0, 0, 1
 6     while n < fmax:
 7         yield b
 8         a,b = b, a+b
 9         n = n + 1
10 
11 if __name__ == "__main__":
12     fs = fibs(10)
13     for i in fs:
14         print(i)

生成器yeild还有几个方法:send(),throw(),close()。以后再说。



原文地址:https://www.cnblogs.com/mafu/p/13540341.html