zoukankan      html  css  js  c++  java
  • python -- 生成器

    在for循环中,每次yield值后,控制权就返回给for循环

    生成器类似于返回一个数组的函数。生成器有参数、可以被调用,并生成值的序列。和函数一次返回整个数组不同,生成器每次只是生成一个值,这样会占用很少的内存,并且调用者可以立即处理生成的值。概括来说,生成器看起来像个函数,但是使用起来像个迭代器。

    Python提供的,在需要时才生成结果的工具:
    -生成器函数:
      使用def定义,但是每次使用yield生成返回值值、挂起、在继续运行。
    -生成器表达式:
      类似于列表推导,但不是创建一个结果列表,而是每次根据需要生成对象。

    因为无论是生成器函数、还是生成器表达式都不是一次生成一个结果列表,这样可以节省内存空间,并将计算时间以迭代协议的方式切分开。

    生成器函数:yield和return
    生成器函数和常规函数有点类似,都是使用def定义。当创建后,自动实现迭代协议。
    常规函数会返回值并退出。而迭代器函数返回一个值后会自动挂起、然后再次执行。
    生成器函数和常规函数之间的主要区别是前者yield一个值,后者返回一个值。yield会挂起函数,返回一个值给调用者。

    生成器是和迭代协议绑在一起的。可迭代的对象定义一个方法:__next__(),该方法要么返回迭代器的下一个值,要么抛出一个异常。

    定义生成器的时候需要使用关键字:yield。

    让我们来看个示例:

    >>> 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()返回一个迭代器对象


    比如,下面的迭代器生成数字的立方值

    >>> 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']
    >>> 
    
  • 相关阅读:
    poj2352树状数组
    hdu1166树状数组
    poj2785双向搜索
    poj2566尺取变形
    poj2100还是尺取
    poj3061尺取法
    poj3320尺取法
    hdu3829最大独立集
    poj2594最小顶点覆盖+传递闭包
    经典换根dp——hdu2196
  • 原文地址:https://www.cnblogs.com/abclife/p/7502431.html
Copyright © 2011-2022 走看看