简单的生成器,生成器解析式:
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语句的函数叫做生成器。是一种用普通函数语法定义的迭代器。上例函数解析:
- myGenerator = myGenerator()。调用函数并把它赋值给变量myGenerator,除了返回生成器外什么都没有做,任何值都不会返回。
- print(myGenerator)。打印一下对象,说明是生成器类型。
- print(type(myGenerator))。查看类型。
- print(dir(myGenerator))。还是查看。
- print(next(myGenerator))。生成器开始执行,遇到第一个yeild语句,将值返回并暂停执行(有的称之为挂起)。
- print(next(myGenerator))。再次调用next(),从上次暂停的位置开始,将值返回,并暂停。
- print(next(myGenerator))。重复上面操作。
- 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()。以后再说。