在for循环中,每次yield值后,控制权就返回给for循环python
生成器相似于返回一个数组的函数。生成器有参数、能够被调用,并生成值的序列。和函数一次返回整个数组不一样,生成器每次只是生成一个值,这样会占用不多的内存,而且调用者能够当即处理生成的值。归纳来讲,生成器看起来像个函数,可是使用起来像个迭代器。shell
Python提供的,在须要时才生成结果的工具:
-生成器函数:
使用def定义,可是每次使用yield生成返回值值、挂起、在继续运行。
-生成器表达式:
相似于列表推导,但不是建立一个结果列表,而是每次根据须要生成对象。数组
由于不管是生成器函数、仍是生成器表达式都不是一次生成一个结果列表,这样能够节省内存空间,并将计算时间以迭代协议的方式切分开。函数
生成器函数:yield和return
生成器函数和常规函数有点相似,都是使用def定义。当建立后,自动实现迭代协议。
常规函数会返回值并退出。而迭代器函数返回一个值后会自动挂起、而后再次执行。
生成器函数和常规函数之间的主要区别是前者yield一个值,后者返回一个值。yield会挂起函数,返回一个值给调用者。工具
生成器是和迭代协议绑在一块儿的。可迭代的对象定义一个方法:__next__(),该方法要么返回迭代器的下一个值,要么抛出一个异常。对象
定义生成器的时候须要使用关键字:yield。blog
让咱们来看个示例:内存
>>> def counter(n): print("counter()") while True: yield n print("increment n") n += 1 >>> c = counter(2) >>> c <generator object counter at 0x000000000246D480> >>> next(c) counter() 2 >>> next(c) increment n 3 >>> next(c) increment n 4 >>> c.next() increment n 5 >>> c.next() increment n 6 >>>
1.关键字yield代表该函数不是一个常规函数,而是一个迭代器函数。
2.生成一个迭代器的实例,和调用常规函数相似。可是调用的时候并不真正执行函数代码。
3.counter()返回一个迭代器对象rem
好比,下面的迭代器生成数字的立方值generator
>>> def cubic_generator(n): for i in range(n): yield i**3 >>> cg = cubic_generator(3) >>> cg <generator object cubic_generator at 0x0000000002A72CF0> >>> cg.next() 0 >>> cg.next() 1 >>> cg.next() 8 >>> cg.next() Traceback (most recent call last): File "<pyshell#32>", line 1, in <module> cg.next() StopIteration >>>
在for循环中,每次yield值后,控制权就返回给for循环:
>>> for i in cubic_generator(5): print(i) 0 1 8 27 64 >>>
若是用return代替yield:
>>> def cubic_generator(n): for i in range(n): return i**3 >>> for i in cubic_generator(5): print(i) Traceback (most recent call last): File "<pyshell#54>", line 1, in <module> for i in cubic_generator(5): TypeError: 'int' object is not iterable >>> cubic_generator(5) 0 >>>
使用生成器的示例1:
>>> def fib(): limit = 10 count = 0 a,b = 0,1 while True: yield a a,b = b,a+b if (count == limit): break count += 1 >>> for i in fib(): print(i) 0 1 1 2 3 5 8 13 21 34 55 >>>
使用生成器实现斐波纳契数列:
>>> def fib(max): a,b = 0,1 while a < max: yield a a,b = b,a+b >>> for i in fib(500): print (i) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 >>> list(fib(500)) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377] >>>
生成器表达式: 可推导的迭代器
迭代器和列表推导相结合,造成了一个新特性:生成器表达式。
生成器表达式和列表表达式相似,可是前者被小括号包含着,后者是用方括号包含的。
>>> #列表推导 >>> [x**3 for x in range(5)] [0, 1, 8, 27, 64] >>> >>> #生成器表达式 >>> (x**3 for x in range(5)) <generator object <genexpr> at 0x0000000002BE0798> >>> >>> list(x**3 for x in range(5)) [0, 1, 8, 27, 64] >>>
>>> gen=(x**3 for x in range(5)) >>> gen.next() 0 >>> gen.next() 1 >>> gen.next() 8 >>> gen.next() 27 >>> gen.next() 64 >>> gen.next() Traceback (most recent call last): File "<pyshell#17>", line 1, in <module> gen.next() StopIteration >>>
生成器:函数 vs 表达式
相同的迭代能够用生成器函数或生成器表达式实现。两者均可以自动迭代或手动迭代。
>>> gen = (c*5 for c in 'pyhton') >>> list(gen) ['ppppp', 'yyyyy', 'hhhhh', 'ttttt', 'ooooo', 'nnnnn'] >>> >>> def gen(x): for c in x: yield c*5 >>> g=gen('python') >>> list(g) ['ppppp', 'yyyyy', 'ttttt', 'hhhhh', 'ooooo', 'nnnnn'] >>>