zoukankan      html  css  js  c++  java
  • python 生成器、列表解析式、yield、迭代器

    开局一张图总结关系
    ![](https://images2018.cnblogs.com/blog/1226829/201808/1226829-20180808170030116-52783735.png)
    一、列表解析式
    我们习惯生成列表通过list = [1, 2, 3]的方式。还有一种很方便的列表生成方式 list = [a*2 for a in range(10)],或者list = [fun(a) for a in range(10)]都是可以的
    >>> L1 = [a*2 for a in range(10)]
    >>> L1
    [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    

    如果只是生成一个100元素,1000元素的列表,那很简单,可是你需要一个100万,一亿个元素的列表时,这样去生成列表,你要知道,它是实实在在的存在你的内存里面,这么大一个列表,过于耗费内存。
    那么有没有什么好的解决办法呢?------------>生成器

    二、生成器
    按照某种算法推算出列表元素,可以一直一边循环一边计算出列表元素的机制,称之为生成器:generator。一个简单生成器构造:列表是L = [a*2 for a in range(10)] 生成器把中括号[]换成小括号()就好了,G = (a*2 for a in range(10)) 这样就得到了一个生成器,[.....]生成列表,(.....)生成生成器
    >>> g = (a*a for a in range(10))
    >>> g
    <generator object <genexpr> at 0x0000001D925F3308>     #1
    >>> for v in g:         #2
    ...     print(v)
     1
    4
    9
    16
    25
    36
    49
    64
    81
    
    在#1处我们生成了一个generator obj ,通过#2 的方式就可以取到当中的元素了。
    
    三、yield
    首先我们来写一个斐波拉契数列 1, 1, 2, 3, 5, 8, 13, 21.....除第一个数外,每前两个数的和等于第三个数
    fib_list = []
    def fib(n):
        i, a, b = 0, 0, 1
        while i < n:
            fib_list.append(b)
            a, b = b, a+b
            i = i + 1
    
    f = fib(6)
    print(fib_list)
    
    #结果为
    [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    

    这样就得到了一个简单斐波拉契数列了。
    当然我们还可以用yield来进行改装,把它变成一个生成器对象,yield: 在函数执行时会给函数返回generator对象,可以通过该对象的obj.next()方法或next(obj)来启动函数

    >>> def generator_example():
    ...     print('before yield')
    ...     yield 'first yield'   
     
    ...     print('after first yield')
    ...     message = yield 'second yield'         #1  调用obj.send('message')可把值赋给yield表达式,同时返回yield右边的内容
     
    ...     print('第二个yield收到send函数的消息:{}'.format(message))
    ...     yield
    ...     return 'over'
    >>> g = generator_example()         #2 运行带yield的函数,返回一个generator obj
    >>> g
    <generator object generator_example at 0x0000006E725E3308>
    >>> res = g.__next__()         #3 调用obj.__next__()方法启动generator
    before yield
    >>> print(res)         
    first yield
    >>> res2 = next(g)         #4 next(obj) 等同于obj.__next__()
    after first yield
    >>> print(res2)
    second yield
    >>> res3 = g.send('form send: after second yield')
    第二个yield收到send函数的消息:form send: after second yield
    >>> print(res3)
    None
    >>> try:
    ...     next(g)
    ...     print('上一个next(g)因为没有yield,所以触发错误,这儿不会执行')
    ... except StopIteration as e:
    ...     print(e.value)
    over
    

    上面没有提到obj.send()方法,#3处第一次通过obj.next()方法启动generator后,函数返回第一个yield右边的值,并停在了哪儿,然后第二次通过next(obj)让函数继续运行到第二个yield,返回second yield然后停住,然后第三次通过obj.send(value)的方法把value传给给了暂停地方的yield表达式的 message,并启动函数继续运行直到遇到下一个yield。......最后当触发最后次yield但是后面没有yield能暂停就报错了,使用try:抓住错误,并接受函数返回值over

    yield来实现斐波拉契数列
    
    def fib(n):
        i, a, b = 0, 0, 1
        while i < n:
            yield b         #在这儿用yield就好了
            a, b = b, a+b
            i = i + 1
        return '--done--'    
    
    f = fib(6)
    while True:
        try:
            res = next(f)
            print(res)
        except    StopIteration as e:
            print(e.value)
            break
    
    #运行结果为
    1
    1
    2
    3
    5
    --done--
    
    四、迭代器
    生成器都是迭代器

    还有可以作用于for循环的数据类型有:
    一类是集合数据类型:如 list、tuple、duct、str等
    另一类是generator包括生成器,和带yield的generator function,这些可以直接作用于for循环的对象统称为可迭代对象(Iterable)可使用isinstance()来判断是否为Iterable

    >>> from collection import Iterable
    >>> isinstance([], Iterable)
    True
    

    而生成器不但可以作用于for循环,还能被next()函数不断调用返回下一个值,直到抛出StopIteration错误无法继续
    可以被next()函数调用并不断返回下一个值的对象就称为迭代器Iterator
    list、idct、str虽然可以用for循环,可迭代,但是没有nex()方法就不是Iterator迭代器

    而使用iter()函数就可以把它们变成迭代器了

    >>> gen_list = iter([1, 3, 5, 7])
    >>> gen_list
    <list_iterator object at 0x00000052371B6C50>
    

    range() 或for line in f:这样的内部也都是封装了迭代器

    人生还有意义。那一定是还在找存在的理由
  • 相关阅读:
    AndroidStudio制作个人资料界面模块以及SQLite数据库的使用
    掌握这13个MySQL索引知识点,让你面试通过率翻倍
    获取数据表最后最后访问,修改,更新,扫描时间
    一本彻底搞懂MySQL索引优化EXPLAIN百科全书
    Win10系统下的MySQL5.7.24版本(解压版)详细安装教程
    解决beego在ubuntu下连接mysql与重置mysql密码
    在Windows上安装MySQL
    docker~dockertoolbox的加速器
    Git 安装 on centos7
    centos7.x中安装SQL Server
  • 原文地址:https://www.cnblogs.com/shiqi17/p/9348581.html
Copyright © 2011-2022 走看看