生成器虽然强大,但生成器的学习并不涉及到Python的魔法方法,甚至还巧妙的避开了类和对象,仅需要通过普通的函数就可以实现。
生成器其实是迭代器的一种实现,生成器的发明一方面使Python更为简洁,另一方面生成器使Python模仿协同程序的概念得以实现。
所谓的协同程序就是可以运行的独立函数调用,函数可以暂停或者挂起,并在需要的时候从程序离开的地方继续或者重新开始。
对于一个普通的函数,我们调用它一般都是从函数的第一句开始,结束于return语句,或者异常,或者函数所有的语句都执行完。一旦函数将控制权交还给调用者,就意味着函数全部结束了。而生成器是一个特殊的函数,调用可以中断、暂停。中短暂停之后,把控制权临时交出来,在需要的时候能重新获取控制权,从上一次中断的地方继续下去。
>>> def MyGen():
print("生成器被执行")
yield 1 #一旦函数里出现yield语句,就说明这个函数被定义为生成器。yield相当于函数的return语句,但是普通函数一返回就结束,但对于生成器,出现yield会把yield后面的参数返回出去,然后暂停在yield的地方,下次执行再从这里开始
yield 2
>>> myG = MyGen()
>>> next(myG)
生成器被执行
1
>>> next(myG)
2
>>> next(myG)
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
next(myG)
StopIteration
>>> for i in MyGen(): #Python的for循环会自动调用next方法,并探测StopIteration
print(i)
生成器被执行
1
2
Python3除了有列表推导式外还有字典推导式,集合推导式
>>> b = {i : i % 2 == 0 for i in range(10)} #有冒号是字典,没冒号是集合
>>> b
{0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}
>>> c = {i for i in [1,1,3,2,4,3,2,6,5,1]} #不会显示重复数字
>>> c
{1, 2, 3, 4, 5, 6}
那元组推导式呢?
>>> e = (i for i in range(10))
>>> e
<generator object <genexpr> at 0x00000000033BAC50> #实际上用圆括号()括起来的推导式是生成器推导式
测试:
>>> next(e)
0
>>> for each in e:
print(each, end=" ")
1 2 3 4 5 6 7 8 9
生成器推导式如果作为函数的参数传入,,可以直接写推导式,不用写圆括号:
>>> sum((i for i in range(100) if i % 2)) #带括号
2500
>>> sum(i for i in range(100) if i % 2) #不带括号
2500