• 迭代器和生成器


    迭代器

    可以把迭代器比喻成一个容器,可以从这个容器中一个接一个的把值取出来,取值的过程就是可迭代的过程

      可迭代协议:含有__iter__方法

      迭代器协议:含有__iter__方法 且 __next__方法

      查看方法:print(l1.__dir__)


    可迭代对象: 含有__iter__方法 

    迭代器: 含有__iter__方法和__next__方法 迭代器.__next__ 调用迭代器


    (迭代器 是 可迭代对象 的 子集)


    第一种判断方法:

      判断是不是可迭代:print('__iter__' in dir(对象)) 对象可以是字符串、列表、字典、等等

      判断是不是迭代器:print('__next__' in dir(对象)) 

    第二种判断方法:

    from collections import Iterable
    
    from collections import Iterator
    print(isinstance(对象,Iterable))   # 判断是不是可迭代的
    print(isinstance(对象,Iterator))   # 判断是不是迭代器

    例如:

    li = []
    a = li.__iter__()
    from collections import Iterator
    from collections import Iterable
    print(isinstance([1,2],Iterable))       #从功能上判断    而type()是类型  是就是  不是就不是
    print(isinstance([1,2],Iterator))
    print(isinstance(a,Iterator))
    # True
    # False
    # True

    迭代器的特点:
      从前往后依次去取值,不可逆,不可重复
      惰性运算
      节省内存

    取值超出范围,会抛出一个异常:

    li = [1,2,3,4,5]
    li_iter = li.__iter__()
    print(li_iter.__next__())
    print(li_iter.__next__())
    print(li_iter.__next__())
    print(li_iter.__next__())
    print(li_iter.__next__())
    print(li_iter.__next__())
    #Traceback (most recent call last):
    #  File "D:/Demo/test2.py", line 26, in <module>
    #    print(li_iter.__next__())
    #StopIteration                                 超出5次  报错 StopIteration

    while 模拟 for

    li = [1,2,3,4,5]
    li_iter = li.__iter__()
    while True:
        try:
            print(li_iter.__next__())
    
        except StopIteration:          #StopIteration  报出异常
            break

    python3内置迭代器:

        内置迭代器:range() file(文件for循环读) enumerate()

    生成器

    生成器的本质: 就是 迭代器 内含__next__()方法,

    一个函数里面如果有yield,那么这个函数就是生成器函数

    def ge_iter():              #ge_iter()  就是生成器函数           生成器函数  里面有    yield关键字
        print('aa')
        yield 11        # 见到yield 取一次值,且记住这个位置,下次直接从这里开始
        print('bb')
        yield 15
        yield 1
        yield 2
    g = ge_iter()         # ge_iter()是生成器               生成器就是迭代器,能用__next__方法取值
    print(g.__next__())
    # aa
    # 11

    while取值:

    def ge_iter():
        print('aa')
        yield 11
        print('bb')
        yield 15
        yield 1
        yield 2
    g = ge_iter()           调用ge_iter()不会立即执行,而是返回一个生成器
    while True:
        try:
            print(g.__next__())
        except StopIteration:
            break

    for循环取值:

    def ge_iter():
        for i in range(10):
            yield "我是第{}名".format(i)
    g = ge_iter()
    print(g.__next__())
    print(g.__next__())
    for i in range(3):                # for循环取一段值
        print(g.__next__())      # 会接着上次保存的位置,接着取值
    # 我是第0名
    # 我是第1名
    # 我是第2名
    # 我是第3名
    # 我是第4名

    生成器惰性特点:

    def fuc1(n,i):
        return n + i
    def duoxing():
        for i in range(4):
            yield i
    g = duoxing()
    for n in [1,10]:
        g = (fuc1(n,i) for i in g)    关键点:因为生成器不取值(不打印),就永远不去运算,不运算,但for不停,
                                                所以最后 g = (fuc1(n,i) for i in (fuc1(n,i) for i in duoxing()))   
    print(list(g))                      直接把 n = 10 带入计算
    # [20, 21, 22, 23]

    生成器取值,取了就没了:

    def fuc1(n,i):
        return n + i
    def duoxing():
        for i in range(4):
            yield i
    g = duoxing()
    for n in [1,10]:
        g = (fuc1(n,i) for i in g)                                               
        print(list(g))                          第一次取值了,g生成器就没了            不管循环多少次,只有第一次有值,取空了,后面都是空列表
    
    #[1, 2, 3, 4]
    #[]

    ==

    一个生成器如下:

    def cloth():
        for i in range(100):
            yield ‘衣服%’%i
    g = cloth()

    取值:

    for i in g: 
        print(i)
    
    #等价于
    
     for i in range(100):
        print(g.__next__())  #循环触发打印100次

    for 自动触发可迭代g内部next方法 想当于第二个手动触发

    为什么用for 是因为 next() 和send()有可能遇到取完再取的报错

    而for循环取完就停止了

    示例:文件的监视,监听文件的变化

    def tail():
        f = open('文件','r',encoding='utf-8')
        f.seek(0,2)      #把光标定位到文件末尾
        while True:
            line = f.readline()  #从光标的位置读
            if line:         #line如果有内容  True
                yield line
            import time
            time.sleep(0.1)
    g = tail()
    for i in g:
        print(i.strip())
    ##注意 文件输入一定要保存 要不然显示不出来

    send()方法

    __send__() 可以写成send()
    __next__() 可以写成next()

    def f1():
        a = 1
        b = yield a   #执行到yield a 停止  返回a = 1    ***    send传值,想当于把yield a 替换 , 变成b = 5 ,继续往下走
        yield b   #定位到yield b   又停止,返回 b = 5
    g = f1()
    print(next(g))
    print(g.send(5))
    #1
    #5

    send 想当于next的同时传参( send(None) == next() ) 把生成器里面yield及后面的值整体替换成传入的参数

    send不能 用在第一个触发生成器

    next + send 数量和 = yield 数量

    预激活装饰器

    正常情况,需要用next()方法取值一次,才能用send()方法

    #每传一个数,求每次传入后的平均值
    def average():
        sum = 0
        count = 0
        aver_age = None
        while True:
            count += 1
            a = yield aver_age
            sum += a
            aver_age = sum/count
    
    g_aver = average()
    print(g_aver.__next__())
    print(g_aver.send(10))
    print(g_aver.send(20))
    print(g_aver.send(30))
    #10
    #15
    #20

    可以利用装饰器,把第一个next()方法放到装饰器里面

    def init(func):
        def inner(*args,**kwargs):
            g = func(*args,**kwargs)
            next(g)
            return g         #这个地方一定要返回一个生成器
        return inner
    @init
    def average():
        sum = 0
        count = 0
        aver_age = None
        while True:
            count += 1
            a = yield aver_age       #yield后面放什么都行,这个主要是只要一个yield,来返回aver_age 的值
            sum += a
            aver_age = sum/count
    
    g_aver = average()       #得到生成器,并赋值给g_aver,这一步不能省略,如果写成print(average.send(10)),想当于每次都重新调用average函数
    # print(g_aver.__next__())   #这一步放到装饰器函数里面,预激活
    print(g_aver.send(10))
    print(g_aver.send(20))
    print(g_aver.send(30))

    yield from   

    代替for 循环

    for i in a:

      yield i

    for i in a:
        yield i
    
    # 等价于
    
    yield from a

    示例:

    a = ‘abcd’  依次拿到‘a''b''c''d'
    def func():
        a = 'abcd'
        for i in a:    #这
            yield i     #两句
    g = func()
    print(list(g))
    # ['a', 'b', 'c', 'd']
    
    ------
    
    def func():
        a = 'abcd'
        yield from a   #这一句
    g = func()
    print(list(g))
    # ['a', 'b', 'c', 'd']
  • 相关阅读:
    D. Babaei and Birthday Cake--- Codeforces Round #343 (Div. 2)
    Vijos P1389婚礼上的小杉
    AIM Tech Round (Div. 2) C. Graph and String
    HDU 5627Clarke and MST
    bzoj 3332 旧试题
    codeforces 842C Ilya And The Tree
    codesforces 671D Roads in Yusland
    Travelling
    codeforces 606C Sorting Railway Cars
    codeforces 651C Watchmen
  • 原文地址:https://www.cnblogs.com/jin-yuana/p/10024929.html
Copyright © 2020-2023  润新知