生成器就是一个函数,python中带yield关键字的函数就是一个生成器。yield语句就是返回一个对象(值),和普通的函数用return返回值不同如果想取得值,那得调用next()函数,如:
每当调用一次迭代器的next函数,生成器函数运行到yield之处,返回yield后面的值且在这个地方暂停,所有的状态都会被保持住,直到下次next函数被调用,或者碰到异常循环退出。
生成器在内部记住了记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量和函数参数都保持不变。生成器不仅“记住”了它的数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。
其实说白了就是,生成器记录了上次调用的数据与执行流程。
- def fib(max):
- a, b = 1, 1
- while a < max:
- yield a
- 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):
- print "iter"
- self.a = 0
- self.b = 1
- return self
- def next(self):
- 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
-
-
- 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),所以在列表比较长的情况下使用内存上更有效。