zoukankan      html  css  js  c++  java
  • Python学习札记(十八) 高级特性4 生成器

    参考:生成器

    Note

    1.通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的,且容易造成空间浪费。所以,如果列表元素可以按照某种算法推算出来,那我们可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间,在Python中这种机制称为生成器:generator。

    注意:generator保存的是算法。

    第一种生成generator的方法很简单,将列表生成式的[]括号改为()即可:

    #!/usr/bin/env python3
    
    L = [i*i for i in range(1, 11)]
    
    G = (i*i for i in range(1, 11))
    
    print(L)
    
    print(G)
    
    sh-3.2# ./generator1.py 
    [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
    <generator object <genexpr> at 0x101be17d8>
    

    如果想要一个一个打印出来generator的元素,可以借助next()函数来访问。

    >>> g = (i*i for i in range(1, 11))
    
    >>> next(g)
    1
    >>> next(g)
    4
    >>> next(g)
    9
    >>> next(g)
    16
    >>> next(g)
    25
    >>> next(g)
    36
    >>> next(g)
    49
    >>> next(g)
    64
    >>> next(g)
    81
    >>> next(g)
    100
    >>> next(g)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    

    generator保存的是算法,在调用next()函数的时候是先用保存的算法计算得到值再输出。next()函数在越界的时候报“StopIteration”错误。

    但是= =,generator基本不用next()函数。一般使用for循环输出元素。

    for i in G :
    	print(i)
    
    1
    4
    9
    16
    25
    36
    49
    64
    81
    100
    

    2.generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

    比如斐波那契数列:

    def fib(maxn) :
    	i, a, b = 1, 1, 1
    	print(1)
    	while i < maxn:
    		print(b)
    		a, b = b, a+b
    		i = i+1
    

    输出斐波那契数列的前n个数。

    >>> from generator1 import fib
    
    >>> fib(5)
    1
    1
    2
    3
    5
    
    >>> fib(10)
    1
    1
    2
    3
    5
    8
    13
    21
    34
    55
    

    注意语句:i, a, b = 1, 1, 1

    仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

    也就是说,这种算法也可以通过generator的方法进行保存。

    改动为generator也很简单:print(b) => yield(b)。

    def fib1(maxn) :
    	i, a, b = 0, 0, 1
    	while i < maxn:
    		yield(b)
    		a, b = b, a+b
    		i = i+1
    
    >>> from generator1 import fib1
    >>> fib1(5)
    <generator object fib1 at 0x101be18e0>
    >>> fib1(10)
    <generator object fib1 at 0x101be1938>
    

    这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

    注意理解这段话:

    • 1.generator在使用next()的时候基于保存的算法进行计算并执行语句;
    • 2.generator在遇到yield(n)语句的时候返回n;
    • 3.再次用next()调用generator时,从上一个返回的yield语句开始执行。
    def exp():
    	print('step 1:')
    	yield(1)
    	
    	print('step 2:')
    	yield(3)
    
    	print('step 3:')
    	yield(5)
    

    exp()函数内含yield()语句,因而是一个generator。

    >>> from generator1 import exp
    >>> exp()
    <generator object exp at 0x1013e1938>
    

    调用exp()函数时,需要先创建一个generator对象,并通过next()函数执行generator。

    >>> output = exp()
    
    >>> print(next(output))
    step 1:
    1
    
    >>> print(next(output))
    step 2:
    3
    
    >>> print(next(output))
    step 3:
    5
    
    >>> print(next(output))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    

    因此,generator在调用next()函数时执行,在遇见yield()语句时返回。

    当然,我们在函数也尽量避免使用next()函数,使用迭代取代next。

    >>> for i in fib1(5):
    ...     print(i)
    ... 
    1
    1
    2
    3
    5
    

    练习:

    杨辉三角定义如下:

              1
            1   1
          1   2   1
        1   3   3   1
      1   4   6   4   1
    1   5   10  10  5   1
    

    把每一行看做一个list,试写一个generator,不断输出下一行的list:

    My Answer:

    def triangles():
    	i = 1
    	L = []
    	while i <= 10:
    		L1 = []
    		L1.append(1)
    		
    		if i > 1 :
    			for j in range(1, i-1):
    				# print('i', i, 'j', j)
    				a, b = int(L[j]), int(L[j-1])
    				# print(a, b)
    				L1.append(a+b)
    
    		if i > 1 : 
    			L1.append(1)
    		
    		yield(L1)
    		i = i+1
    		L = L1
    
    n = 0
    
    for t in triangles():
        print(t)
        n = n + 1
        if n == 10:
            break
    
    
    [1]
    [1, 1]
    [1, 2, 1]
    [1, 3, 3, 1]
    [1, 4, 6, 4, 1]
    [1, 5, 10, 10, 5, 1]
    [1, 6, 15, 20, 15, 6, 1]
    [1, 7, 21, 35, 35, 21, 7, 1]
    [1, 8, 28, 56, 70, 56, 28, 8, 1]
    [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
    sh-3.2# 
    

    2017/2/7

  • 相关阅读:
    project
    类欧几里得算法
    还不熟悉的内容
    Hall定理
    FWT学习笔记
    最小树形图
    BZOJ 3027 [Ceoi2004]Sweet
    多项式除法
    VUE 计算属性和侦听器
    VUE 模板语法
  • 原文地址:https://www.cnblogs.com/qq952693358/p/6374880.html
Copyright © 2011-2022 走看看