zoukankan      html  css  js  c++  java
  • 生成器,迭代器

    先有个列表生成式

    看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],我要求你把列表里的每个值加1,你怎么实现?

    >>> a
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> b = []
    >>> for i in a:b.append(i+1)
    ... 
    >>> b
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    >>> a = b
    >>> a
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    普通方法一
    a = [1,3,4,6,7,7,8,9,11]
    
    for index,i in enumerate(a):
        a[index] +=1
    print(a)
    
    原值修改
    普通方法二
    >>> a
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    >>> a = map(lambda x:x+1, a)
    >>> a
    <map object at 0x101d2c630>
    >>> for i in a:print(i)
    ... 
    3
    5
    7
    9
    11
    文艺青年
    >>> a = [i+1 for i in range(10)]
    >>> a
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    装逼青年

    这就是列表生成器

    生成器 

    生成器的目的是为了节省内存,提高运算效率,一边生成一边计算的机制,generator。

    1,只有在调用时才会生成相应的数据。

    2,只记录当前位置。

    3,只有一个__next__()方法。

    4,生成关键字yield,一个函数一旦有了yeid,他就是一个generator

    例子:

    def fib(max):
        n,a,b = 0,0,1
    
        while n < max:
            #print(b)
            yield  b
            a,b = b,a+b      #这里是写法要注意
    
            n += 1
    
        return 'done' 
    a=fib(10)
    print(a.__next__())
    print(a.__next__())
    print(a.__next__())
    print("中间可以干别的,互不干扰,不需要死等一个循环结束")
    print(a.__next__())
    print(a.__next__())
    print(a.__next__())

    还可通过yield实现在单线程的情况下实现并发运算的效果

    import time
    def consumer(name):
        print('%s准备吃包子'%name)
        while True:
            baozi =yield
            print('包子%s被%s吃了'%(baozi,name))
    
    def produce(name_produce):
        c=consumer('猴哥')
        c2=consumer('大黄')
        c.__next__()
        c2.__next__()
        for i in range(10):
            time.sleep(1)
            print('包子做好了,掰开给他俩吃')
            c.send(i)
            c2.send(i)
    
    produce('qiangql')

    迭代器

    我们已经知道,可以直接作用于for循环的数据类型有以下几种:

    一类是集合数据类型,如listtupledictsetstr等;

    一类是generator,包括生成器和带yield的generator function。

    这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

    可以使用isinstance()判断一个对象是否是Iterable对象:

    >>> from collections import Iterable
    >>> isinstance([], Iterable)    #列表
    True                
    >>> isinstance({}, Iterable)    #字典
    True
    >>> isinstance('abc', Iterable)  #字符串
    True
    >>> isinstance((x for x in range(10)), Iterable)   #生成器
    True
    >>> isinstance(100, Iterable)
    False  

    而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

    *可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

    可以使用isinstance()判断一个对象是否是Iterator对象:

    >>> from collections import Iterator
    >>> isinstance((x for x in range(10)), Iterator)  #这里只有生成器是迭代器,因为他有返回值
    True
    >>> isinstance([], Iterator)
    False
    >>> isinstance({}, Iterator)
    False
    >>> isinstance('abc', Iterator)
    False

    生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

    listdictstrIterable变成Iterator可以使用iter()函数:

    你可能会问,为什么listdictstr等数据类型不是Iterator

    这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

    Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

    例子

    from collections import Iterator
    a=[1,2,3]
    b=iter(a)
    print(type(b))
    print(b.__next__())
    print(b.__next__())
    print(b.__next__())
    print(b.__next__()) #第四次报错

     

    总结

    凡是可作用于for循环的对象都是Iterable类型;

    凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

    集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

  • 相关阅读:
    利用 PhpStorm、Idea 等 IDE 如何 运行/调试 Go 程序 ?
    [Go] 函数/方法 的 变参
    PHP 如何显示大数字,防止显示为 科学计数法 形式
    PHP协程 详解
    [Go] 路径、目录名、包名、文件名
    [Go] 复合类型(数组、切片、字典、结构体)变量的 初始化 及 注意事项
    Firefox 及其 插件“个性化设置”备份
    Go
    [Go] template 常用方法详解 及 注意事项
    Go
  • 原文地址:https://www.cnblogs.com/PYlog/p/8677472.html
Copyright © 2011-2022 走看看