生成器就是一个函数,python中带yield关键字的函数就是一个生成器。yield语句就是返回一个对象(值),和普通的函数用return返回值不同如果想取得值,那得调用next()函数,如:
c = h() #h()包含了yield关键字
#返回值
c.next()
生成器在内部记住了记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量和函数参数都保持不变。生成器不仅“记住”了它的数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。
其实说白了就是,生成器记录了上次调用的数据与执行流程。
def fib(max):
a, b = 1, 1
while a < max:
yield a #generators return an iterator that returns a stream of values.
a, b = b, a+b
print "a=",a,"b=",b
for n in fib(15):
print n
通过使用生成器的语法,可以免去写迭代器类的繁琐代码,如,上面的例子使用迭代类来实现,代码如下:
class Fib:
def __init__(self, max):
self.max = max
def __iter__(self): #定制可迭代类重载__iter__
print "iter"
self.a = 0
self.b = 1
return self
def next(self): #定制可迭代类重载next()
print "next"
fib = self.a
if fib > self.max:
raise StopIteration
self.a, self.b = self.b, self.a + self.b
return fib
for i in Fib(5):
print i
#yield其他例子展示:排列,组合
#生成全排列
def perm(items, n = None):
if n is None:
n = len(items)
for i in range(len(items)):
v = items[i:i+1]
if n==1:
yield v
else:
rest = items[:i] + items[i+1:]
for p in perm(rest, n-1):
yield v + p
def comb(items, n = None):
if n is None:
n = len(items)
else:
for i in range(len(items)):
v = items[i:i+1]
if 1 == n:
yield v
else:
rest = items[i+1:]
for c in comb(rest, n-1):
yield v + c
生成器语法
生成器表达式是在python2.4中引入的,当序列过长, 而每次只需要获取一个元素时,应当考虑使用生成器表达式而不是列表解析。
生成器表达式的语法和列表解析一样,只不过生成器表达式是被()括起来的,而不是[],如下:
(expr for iter_var in iterable)
(expr for iter_var in iterable if cond_expr)
>>> L= (i + 1 for i in range(10) if i % 2)
>>> L
<generator object <genexpr> at 0xb749a52c>
>>> L1=[]
>>> for i in L:
... L1.append(i)
...
>>> L1
[2, 4, 6, 8, 10]
生成器表达式并不真正创建数字列表, 而是返回一个生成器,这个生成器在每次计算出一个条目后,把这个条目“产生”(yield)出来。
生成器表达式使用了“惰性计算”,只有在检索时才被赋值( evaluated),所以在列表比较长的情况下使用内存上更有效。