zoukankan      html  css  js  c++  java
  • 生成器、迭代器理解

    一、yield工作原理

    
    def consumer():
        r = ''
        while True:
            n = yield r     # 第2步:yield接收,n=None # 第4步:n=1  # 第6步:返回 r="200 OK";  备注: "n"是收到生产者的数据(赋值给"n"),"r"是返回给生产者的数据.
            if not n:
                return
            print('[消费者] Consuming %s...' % n)  #第4步:打印 n=1
            r = '200 OK'  # 第5步:赋值
    
    def produce(c):
        # 注意:next(c) 和 c.send(None)是相等的
        c.send(None)       # 第1步. 唤醒consumer进入到yield
        n = 0
        while n < 5:
            n = n + 1
            print('[生产者] Producing %s...' % n)
            r = c.send(n)  # 第3步. 发送数据"1"给comsumer中的yield  # 第7步.收到r="200 OK"
            print('[生产者] Consumer return: %s' % r)       # 打印r值
        c.close()
    
    c = consumer()
    produce(c)
    
    # yield有3个作用
    # 1. 冻结
    # 2. 返回数据
    # 3. 接收数据
    
    # yield工作过程
    # 1. c.send(1)传值给yield,yield先赋值给n然后向下运行。
    # 2. 通过while循环再次遇到yield后,则返回yield后面r的值。
    
    
    

    二、迭代器

    1. 有__iter__()方法的对象叫Iterable。 如:tuple list dict string set open(file) 
    2. 有__next__()和__iter__()方法的对象叫迭代器对象。  如:open(file)
    3. 迭代器对象一定是可迭代对象, 而可迭代对象不一定是迭代器对象。
    4. 有了迭代器我们可不依赖索引取值了。
    
    #基于for循环,我们可以完全不再依赖索引去取值了
    dic={'a':1,'b':2,'c':3}
    for k in dic:
        print(dic[k])
    
    #for循环的工作原理
    #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
    #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
    #3: 重复过程2,直到捕捉到异常StopIteration,结束循环
    
    #优点:
      - 提供一种统一的、不依赖于索引的迭代方式
      - 惰性计算,节省内存
    #缺点:
      - 无法获取长度(只有在next完毕才知道到底有几个值)
      - 一次性的,只能往后走,不能往前退
    

    三、生成器

    1. 只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码
    2. 生成器就是特殊的迭代器
    

    例:

    1、自定义函数模拟range(1,7,2)

    2、模拟管道,实现功能:tail -f access.log | grep '404'

    #题目一:
    def my_range(start,stop,step=1):
        while start < stop:
            yield start
            start+=step
    
    #执行函数得到生成器,本质就是迭代器
    obj=my_range(1,7,2) #1  3  5
    print(next(obj))
    print(next(obj))
    print(next(obj))
    print(next(obj)) #StopIteration
    
    #应用于for循环
    for i in my_range(1,7,2):
        print(i)
    
    #题目二
    import time
    def tail(filepath):
        with open(filepath,'rb') as f:
            f.seek(0,2)
            while True:
                line=f.readline()
                if line:
                    yield line
                else:
                    time.sleep(0.2)
    
    def grep(pattern,lines):
        for line in lines:
            line=line.decode('utf-8')
            if pattern in line:
                yield line
    
    for line in grep('404',tail('access.log')):
        print(line,end='')
    
    #测试
    with open('access.log','a',encoding='utf-8') as f:
        f.write('出错啦404
    ')
    
    

    3、模拟吃饭

    #yield关键字的另外一种使用形式:表达式形式的yield
    def eater(name):
        print('%s 准备开始吃饭啦' %name)
        food_list=[]
        while True:
            food=yield food_list
            print('%s 吃了 %s' % (name,food))
            food_list.append(food)
    
    g=eater('egon')
    g.send(None) #对于表达式形式的yield,在使用时,第一次必须传None,g.send(None)等同于next(g)
    g.send('蒸羊羔')
    g.send('蒸鹿茸')
    g.send('蒸熊掌')
    g.send('烧素鸭')
    g.close()
    g.send('烧素鹅')
    g.send('烧鹿尾')
    
    

    4、通过装饰器初始化yield生成器函数

    (1)、编写装饰器,实现初始化协程函数的功能

    (2)、实现功能:grep -rl 'python' /etc

    
    #题目一:
    def init(func):
        def wrapper(*args,**kwargs):
            g=func(*args,**kwargs)
            next(g)
            return g
        return wrapper
    @init
    def eater(name):
        print('%s 准备开始吃饭啦' %name)
        food_list=[]
        while True:
            food=yield food_list
            print('%s 吃了 %s' % (name,food))
            food_list.append(food)
    
    g=eater('egon')
    g.send('蒸羊羔')
    
    #题目二:
    #注意:target.send(...)在拿到target的返回值后才算执行结束
    import os
    def init(func):
        def wrapper(*args,**kwargs):
            g=func(*args,**kwargs)
            next(g)
            return g
        return wrapper
    
    @init
    def search(target):
        while True:
            filepath=yield
            g=os.walk(filepath)
            for dirname,_,files in g:
                for file in files:
                    abs_path=r'%s\%s' %(dirname,file)
                    target.send(abs_path)
    @init
    def opener(target):
        while True:
            abs_path=yield
            with open(abs_path,'rb') as f:
                target.send((f,abs_path))
    @init
    def cat(target):
        while True:
            f,abs_path=yield
            for line in f:
                res=target.send((line,abs_path))
                if res:
                    break
    @init
    def grep(pattern,target):
        tag=False
        while True:
            line,abs_path=yield tag
            tag=False
            if pattern.encode('utf-8') in line:
                target.send(abs_path)
                tag=True
    @init
    def printer():
        while True:
            abs_path=yield
            print(abs_path)
    
    
    g=search(opener(cat(grep('你好',printer()))))
    # g.send(r'E:CMSaaadb')
    g=search(opener(cat(grep('python',printer()))))
    g.send(r'E:CMSaaadb')
    
    
    

    http://www.cnblogs.com/linhaifeng/articles/7580428.html

  • 相关阅读:
    AE开发 入门教程
    工作空间工厂 打开文件例子
    Delphi IDE使用的一些主要技巧
    动画演示 Delphi 2007 IDE 功能[2]
    Delphi的类与继承
    属性的自动完成
    DELPHI中函数、过程变量的声明与应用
    Delphi回车键切换焦点
    delphi 窗体的创建和释放
    delphi assigned函数的用法
  • 原文地址:https://www.cnblogs.com/wualin/p/9859980.html
Copyright © 2011-2022 走看看