简单的生成器,生成器解析式:
1 #usr/bin/env python3
2 #-*- codign=utf-8 -*-
3
4 myGenerator = (x*x for x in range(10)) #简单的生成器
5 print(type(myGenerator)) #输出
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 inmyGenerator:7 print(i) #输出1-10的平方的结果
再看熟知的list:
1 myList = [x*x for x in range(10)]; #定义列表解析式
2 print(type(myList)) #输出:
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 inmyList:8 print(i) #有输出
9 #第二次循环还是有输出
10 for j inmyList: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 defmyGenerator():2 yield03 yield 1
4 yield 2
5
6 myGenerator =myGenerator()7 print(myGenerator) #输出:
8 print(type(myGenerator)) #输出:
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 defcheckReturn():2 print "Begin......"
3 while n >0:4 print("Before return.")5 returnn6 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 defcheckYeild(n):2 print("Begin to check yield.....")3 while n >0:4 print("Before yeild.")5 yieldn6 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 deffibs(fmax):2 '''
3 Generator for fibonacci sequence4 '''
5 n, a, b = 0, 0, 1
6 while n <7 yieldb8 a b n="n">
10
11 if __name__ == "__main__":12 fs = fibs(10)13 for i infs:14 print(i)
生成器yeild还有几个方法:send(),throw(),close()。以后再说。
7>