列表生成式可以创建列表,但是受内存限制,列表容量时有限的,创建一个巨量元素的列表,不仅占用很大的存储空间,当仅仅访问前几个元素时,后面的绝大多数元素占用的空间都被浪费了。
如果list的元素可以按照算法推算出来,那么就可以在循环的过程中不断推算出后面的元素,这样就不必创建完整的list,从而节省大部分空间。
这种一边循环一边计算的机制,在Python中称为生成器:Generator。
Python可以简单的把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。
创建生成器
    方法一: 把一个列表生成式的[] 改成(),就创建了一个生成器。
   
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> a = [ x * x for x in range(1,10) ]
>>> a       #a是一个list
[1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> a = ( x * x for x in range(1,10) )
>>> a       #a是一个generator
<generator object <genexpr> at 0x7f2523f8bdb0>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    打印generator中的元素,可使用next() 函数获得generator的下一个返回值。
   
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> next(a)
1
>>> next(a)
4
……
………………
>>> next(a)
64
>>> next(a)
81
>>> next(a)     #计算到最后一个元素后,没有更多的元素时,就会抛出错误
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    使用next()函数获取generator元素的方式并不好用,正确的方法是使用for循环,generator也是可迭代对象。
   
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> a = ( x * x for x in range(1,10) )
>>> for n in a:
...     print(n)
...
4
9
16
25
36
49
64
81
>>> 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
但是当推算算法比较复杂时,for循环可能无法实现算法,可以用函数来实现。
   
斐波那契数列中,除第一个和第二个数之外,任意一个数字都可以由前两个数相加得到。这个逻辑用列表生成式写不出来,但是用函数会很容易:
   
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> def fb(long):
...                                 #L = []
...     n, a, b = 0, 0, 1
...     while n < long:
...             print(b)        #L.append(b)
...             a, b = b, a + b
...             n = n + 1
...     return 'End'                 #return print(L)
...
#>>> fb(20)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]         #注释部分是直接生成一个list
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           
            在这里注意一下,赋值语句的逻辑
                a, b = b, a + b
                => t = ( b, a + b )
                     a = t[0]
                     b = t[1]
   
    方法二: 既然生成了list,就距离generator很近了。要把fb()函数变成generator,只需要把print(b) 改为 yield b 就可以了:
   
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> def fb2(long):
...     n, a, b = 0, 0, 1
...     while n < long:
...             yield b
...             a, b = b, a + b
...             n = n + 1
...     return 'End'
...
>>> fb2(100)
<generator object fb2 at 0x7f2523f8bd58>  
>>> a = fb2(100)
>>> next(a)
1
>>> next(a)
1
>>> next(a)
2   
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    如果一个函数定义中包含了 yield 关键字,那么这个函数不再是一个普通函数,而是一个generator。
   
了解一下yield
    先做一个测试函数
            >>> def test():
            ...     print(1)
            ...     yield 1
            ...     print(2)
            ...     yield 2
            ...     print(3)
            ...     yield 3
            ...
            >>> o = test()
            >>> next(o)
            1
            1
            >>> next(o)
            2
            2
            >>> next(o)
            3
            3
            >>> next(o)
            Traceback (most recent call last):
              File "<stdin>", line 1, in <module>
            StopIteration
    可以看到,在generator执行中,遇到yield就中断了,下次又会接着继续执行。当执行了3次之后,已经没有更多yield可以执行时,再次调用next() 就会抛出错误。
    因此在正常循环调用yield过程中,需要给循环设置一个条件来退出循环,不然就会产生一个无限的数列出来。
    同样的,在改成generator后,基本上不会用next()来获取下一个返回值,而是用for循环来迭代:
          >>> for i in fb2(10):
            ...     print(i)
            ...
            1
            1
            2
            3
            5
            8
            13
            21
            34
            55
    但是for循环迭代generator时,拿不到generator的return语句的返回值。(参见fb2()函数定义内容,与上面对fb2() 进行for迭代的结果)
    如果要拿到返回值,就必须捕获StopIteration错误,返回值包含在StopIteration的Value中:
          >>> def fb2(long):
            ...     n, a, b = 0, 0, 1
            ...     while n < long:
            ...             yield b
            ...             a, b = b, a + b
            ...             n = n + 1
            ...     return 'End'
            ...
           
            >>> b = fb2(10)
            >>> while True:
            ...     try:
            ...             x = next(b)
            ...             print('b:', x)
            ...     except StopIteration as err:
            ...             print('Generator return value:',err.value)
            ...             break
            ...
            b: 1
            b: 1
            b: 2
            b: 3
            b: 5
            b: 8
            b: 13
            b: 21
            b: 34
            b: 55
            Generator return value: End   

练习: 输出杨辉三角形。
   
思路:
    每一行的首尾都是1,
    每一行去掉首尾的1之后会发现,n[1] = up[0] + up[1] , n[2] = up[1] + u[p2] ,也就是 n = up[a] + up[a + 1] 
 
def triangles(n):
    a = [1]
    m = 0
    while n > m:
        yield a
        a = [1] + [a[i] + a[i + 1] for i in range(len(a)-1)] + [1]
        m = m + 1
    return  
   
for i in triangles(7):
    print(i)
[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]   

Day10 python高级特性-- 生成器 Generator的更多相关文章

  1. Python高级特性——生成器(generator)

    通过上节的学习,我们知道使用列表生成式,可以直接创建一个列表.但是,有些时候,受到内存的限制等实际情况,列表生成式无法满足.比如,一个长度为1000万的列表,普通内存根本就不够,又或者实际处理的过程中 ...

  2. python高级特性-生成器

    在python中一边循环一边计算的机制成为生成器(generator) 在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行. 生成list > ...

  3. 三、python高级特性(切片、迭代、列表生成器、生成器)

    1.python高级特性 1.1切片 list列表 L=['Mli','add','sal','saoo','Lkkl'] L[0:3]  #即为['Mli','add','sal']  从索引0开始 ...

  4. python高级特性:切片/迭代/列表生成式/生成器

    廖雪峰老师的教程上学来的,地址:python高级特性 下面以几个具体示例演示用法: 一.切片 1.1 利用切片实现trim def trim(s): while s[:1] == " &qu ...

  5. Python高级特性之:List Comprehensions、Generator、Dictionary and set ...

    今天帅气的易哥和大家分享的是Pyton的高级特性,希望大家能和我一起学习这门语言的魅力. Python高级特性之:List Comprehensions.Generator.Dictionary an ...

  6. python高级之生成器&迭代器

    python高级之生成器&迭代器 本机内容 概念梳理 容器 可迭代对象 迭代器 for循环内部实现 生成器 1.概念梳理 容器(container):多个元素组织在一起的数据结构 可迭代对象( ...

  7. 第三篇:python高级之生成器&迭代器

    python高级之生成器&迭代器   python高级之生成器&迭代器 本机内容 概念梳理 容器 可迭代对象 迭代器 for循环内部实现 生成器 1.概念梳理 容器(container ...

  8. Python高级特性(1):Iterators、Generators和itertools(转)

    译文:Python高级特性(1):Iterators.Generators和itertools [译注]:作为一门动态脚本语言,Python 对编程初学者而言很友好,丰富的第三方库能够给使用者带来很大 ...

  9. Python 高级特性介绍 - 迭代的99种姿势 与协程

    Python 高级特性介绍 - 迭代的99种姿势 与协程 引言 写这个笔记记录一下一点点收获 测试环境版本: Python 3.7.4 (default, Sep 28 2019, 16:39:19) ...

随机推荐

  1. 控制算法PID-理解分析1

    以下内容是来自网络上的,本人觉得有道理,拷贝下来,由于没有找到最源头的出处,没有注明来自何方. 转载,下面说法应该更通俗易懂一家庭,每次需要开支的时候丈夫P都要拿卡去取钱.需要多少取多少,因为银行最低 ...

  2. 分布式监控系统之Zabbix网络发现

    前文我们了解了zabbix的宏,自定义item和模板的相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/14013331.html:今天我们来了解下zab ...

  3. Vue3.0 响应式数据原理:ES6 Proxy

    Vue3.0 开始用 Proxy 代替 Object.defineProperty了,这篇文章结合实例教你如何使用Proxy 本篇文章同时收录[前端知识点]中,链接直达 阅读本文您将收获 JavaSc ...

  4. 凭借着这份Spring面试题,我拿到了阿里,字节跳动美团的offer!

      一般问题 1.1. 不同版本的 Spring Framework 有哪些主要功能?   1.2. 什么是 Spring Framework? Spring 是一个开源应用框架,旨在降低应用程序开发 ...

  5. 深度分析:面试腾讯,阿里面试官都喜欢问的String源码,看完你学会了吗?

    前言 最近花了两天时间,整理了一下String的源码.这个整理并不全面但是也涵盖了大部分Spring源码中的方法.后续如果有时间还会将剩余的未整理的方法更新到这篇文章中.方便以后的复习和面试使用.如果 ...

  6. 图片恢复有新招,EasyRecovery预览模式助你快速恢复

    EasyRecovery作为一款数据恢复软件,因其便捷的操作.低廉的价格深受大家的喜爱.EasyRecovery具有"傻瓜式"操作,就算你是第一次接触这款软件,通过主页提示也能很快 ...

  7. 轻松学编曲,论FL Studio的钢琴卷帘功能

    在编曲软件FL Studio中有一个会被经常用到的功能,叫钢琴卷帘,可以用来扒谱.编曲.制作音乐等,并且操作简单,即使不懂乐理也能一样使用.今天,就来带大家认识一下钢琴卷帘. 还没有安装FL Stud ...

  8. guitar pro系列教程(二十一):Guitar Pro在乐谱上的工作【一】

    当我们使用Guitar Pro写好一首乐谱之后,通常在乐谱上还会有哪些操作呢?对于刚接触{cms_selflink page='index' text='Guitar Pro'}的朋友们肯定还是不熟悉 ...

  9. Go-Web编程_表单_0x02_验证表单的输入

    开发Web的一个原则就是,不能信任用户输入的任何信息,所以验证和过滤用户的输入信息就变得非常重要,我们经常会在微博.新闻中听到某某网站被入侵了,存在什么漏洞,这些大多是因为网站对于用户输入的信息没有做 ...

  10. 自定义 JSTLFunction

    复习常用JSTL Function为什么需要自定义Function如何自定义Function,例子:1.在独立的项目中(也可以在web项目中)的类中(比如Functions)编写一个static方法: ...