首先,先看代码:
def add(s, x):
return s + x
def gen():
for i in range(4):
yield i
base = gen()
for n in [1, 10]:
base = (add(i, n) for i in base)
print list(base)
输出的结果是【20,21,22,23】,也许你会有其他答案
那么怎么得出来的呢?
说到生成器,你必须要知道迭代器(iterator),它只能迭代一次,且遵从迭代器协议:
1.定义了__iter__
方法,但是必须返回自身
2.定义了next方法,在python3中是__next__
,用来返回下一个值,当没有数据可返回时,会抛出一个StopIteration错误
3.可以保持当前的状态
样例
自定义iterator 如何让自定义的类的对象成为迭代器对象,其实就是定义__iter__
和next
方法:
class DataIter(object):
def __init__(self, *args):
self.data = list(args)
self.ind = 0
def __iter__(self): #返回自身
return self
def next(self): # 返回数据
if self.ind == len(self.data):
raise StopIteration
else:
data = self.data[self.ind]
self.ind += 1
return data
那么为什么可以使用for来迭代迭代器对象呢,原因就是for替我们做了next的活,以及接收StopIteration的处理。
迭代器大概如此,下面介绍主角:优雅的迭代器——生成器(generator)。
首先,因为生成器遵循了迭代器协议,所以生成器也是一种迭代器
创建生成器的方式有两种:
1.yield
生成器函数跟普通函数只有一点不一样,就是把 return 换成yield,其中yield是一个语法糖,内部实现了迭代器协议,同时保持状态可以挂起。如下:
记住一点,yield是数据的生产者,而诸如for等是数据的消费者。
def gen():
print 'begin: generator'
i = 0
while True:
print 'before return ', i
yield i
i += 1
print 'after return ', i
a = gen()
a.next()
首先,看到while True
时不比惊慌,它只会一个一个被动的执行,不会主动去执行。当调用gen()时,并没有真实执行函数,而是只是返回了一个生成器对象。执行第一次a.next()时,才真正执行函数,执行到yield一个返回值,然后就会挂起,保持当前的名字空间等状态。然后等待下一次的调用,从yield的下一行继续执行。说白了就是你需要数据(被检索)的时候,才会执行。
2.生成器表达式
a = (i for i in range(10))
生成器表达式会创建一个生成器,而且生成器有个特点就是惰性计算, 只有在被检索时候,才会被赋值,正如上边所说。
再来看一个例子:
def multipliers():
return (lambda x : i * x for i in range(4))
print [m(2) for m in multipliers()]
输出结果为【0,2,4,6】,不清楚则可以看以下等价写法:
def multipliers():
for x in range(4):
def cd(i):
return x*i
yield cd
print [m(2) for m in multipliers()]
但是需要注意以下例子
def multipliers():
return [lambda x : i * x for i in range(4)]
print [m(2) for m in multipliers()]
此例输出为【6,6,6,6】而不是【0,2,4,6】,原因是因为闭包的延迟绑定。当循环结束时,i 的值已经是3, 此时结果都是6。不清楚可以看以下等价写法:
def multipliers():
res = []
for i in range(4):
def inner(j):
return j * i
res.append(inner)
return res
print [m(2) for m in multipliers()]
一个解决的方法便是,使用默认参数绑定数值,如下:
def multipliers():
res = []
for i in range(4):
def inner(j, i = i):
return j * i
res.append(inner)
return res
print [m(2) for m in multipliers()]
或者:
def multipliers():
return [lambda x, i = i : i * x for i in range(4)]
print [m(2) for m in multipliers()]
参考页:http://shomy.top/2016/02/28/python-default-para/
https://segmentfault.com/a/1190000004554823