• Python之生成器


    迭代器

    使用方式

    在Python中只要包含 __iter__()__next__()方法即属于迭代器,前者返回迭代器对象,后者返回迭代器对象所对应的值,直到引发 StopIteration异常结束

    最简单的方法,使用内置的方法 iter(),其返回常用类型的迭代器包装对象

    class Data:
        def __init__(self):
            self.datas = []
    
        def add(self, x):
            self.datas.append(x)
    
        def data(self):
            return iter(self.datas)
    
    
    d = Data()
    
    d.add(1)
    
    d.add(2)
    
    d.add(3)
    
    print(type(d.data()))
    
    for x in d.data():
        print(x)
    

    image-20210419214456947

    自定义迭代器

    返回迭代器对象代替 self.datas列表,可避免对象状态被外部所修改,如果使用 tuple需要复制整个列表,浪费更多的内存

    iter()很方便,但无法让迭代中途停止,这需要自己手动实现迭代器对象,将迭代器从数据对象中分离出去,防止迭代器需要维持状态,同时可能多个迭代器在同时操控数据,这些不该成为数据对象的负担,提升复杂度

    from collections import Iterable
    
    
    # 自定义迭代对象
    class Data:
        def __init__(self):
            self.items = []
    
        def append_items(self, data):
            self.items.append(data)
    
        # 定义iter方法 返回对应的迭代器
        def __iter__(self):
            return DataIterator(self.items)
    
    
    # 自定义迭代器对象
    class DataIterator:
        # 在类里面定义__iter__和__next__方法创建的对象就是迭代器对象
        def __init__(self, items):
            self.items = items
            self.current_index = 0
            
        # 迭代器取值
        def __next__(self):
            print("当前容器对象:%s" % self.items)
            if self.current_index >= len(self.items):
                raise StopIteration
    
            value = self.items[self.current_index]
            self.current_index += 1
            return value
    
    
    if __name__ == '__main__':
        data = Data()
        data.append_items(11)
        data.append_items(12)
        data.append_items(13)
    
        print(data)
    
        res = isinstance(data, Iterable)
        print('是否为可迭代对象:%s' % res)
        for i in data:
            print("迭代器取值:%s" % i)
    

    image-20210419225628936

    在上述代码中Data仅仅为数据容器只需要使用 __iter__返回迭代器对象即可,而由DataIterator提供 __next__方法进行数据取值,除了使用for循环进行取值,迭代器也可以使用 __next__取值

        it = iter(data)
        
        for i in range(4):
            print(it.__next__())
        
    

    image-20210419230528217

    生成器

    基于索引实现的迭代器有些丑陋,更合理的的做法使用 yield返回实现了迭代器协议的 Generator对象

    class Data:
        def __init__(self):
            self.items = []
    
        def add(self, data):
            self.items.append(data)
    
        def __iter__(self):
            for i in self.items:
                yield i
    
    
    d = Data()
    d.add(11)
    d.add(12)
    d.add(13)
    print(d)
    
    # 编译器会将包含 `yield`方法的函数进行重新打包,时期返回 ` Generator`对象
    print(d.__iter__())
    
    for x in d:
        print(x)
    
    

    image-20210419234604787

    协程

    yield实现生成 Generator涉及到协程的工作原理

    def crountinnne():
        print('croutine start')
        
        result = None
        
        while True:
            
            res = yield result
            
            print(res)
            
            result = res.split(",")
            
    c = crountinnne()
    
    c.send(None)
    
    c.send('a,b')
    

    image-20210420230843303

    • 创建协程对象,必须使用 send(None)或者 Next对象启动协程
    • 协程在执行到 res = yield result的时候将程序挂起,等待消息
    • 调用方发送 'a,b'消息,协程恢复执行,将接收消息保存给 res,继续执行接下流程
    • 程序再次循环到 yield将上次处理结果返回,再次将程序挂起,等待消息
    • 直到程序结束或者引发异常
    # 关闭协程
    c.close()
    
    # 无法发送消息
    c.send('c,d')
    

    image-20210420232857978

    close可以引发协程 GeneratorExit使其正常退出,而 throw可以引发任何类型的异常

    模式

    生产消费模型

    利用 yield协程特性,进行生产者消费者模型

    def consumer():
        while True:
            d = yield
            if not d:
                break
            print("消费者开启:%s" % d)
    
    # 创建消费者
    c = consumer()
    
    # 启动消费者
    c.send(None)
    
    c.send(1)
    
    c.send(2)
    
    c.send(3)
    
    # 生产结束 通知消费者结束
    c.send(None)
    

    image-20210422202157717

    异步回调

    回调函数是异步操作常用的手段,使用 yield完全可以使用 blocking style(非阻塞)进行异步操作

    下列代码中首先 framework是主函数,调用 logic函数,当 logic函数被调用接受到某个结果或者信号的时候,会使用 callback函数进行结果返回,但是此种方法被拆分到两个函数里,业务逻辑不清晰

    def framework(logic,callback):
        s = logic()
        
        print("logic函数开始运行:%s" % logic)
        
        print("framework函数开始运行")
        
        # 调用回调函数返回结果
        callback("async:%s" % s)
    
    def logic():
        s = 'logic'
        return s
    
    def callback(s):
        print(s)
    
    framework(logic,callback)
    

    image-20210423081454105

    使用 yield进行 blockins style回调

    def framework(logic):
        try:
            # 获取生成器
            it = logic()
            
            print(it)
            
            # 获取生成器的值
            s = next(it)
           
            print("logic函数运行:%s" % s)
    
            print("framework处理任务:")
            
            # 对回调函数发送信号
            it.send("async:%s" % s)
            
        except StopIteration:
            # 遇到异常 打破循环
            pass
        
    def logic():
        s = 'mylogic'
        res = yield s
        print(res)
    
    framework(logic)
    

    image-20210423090940746

  • 相关阅读:
    Beta阶段团队成员贡献分分配规则
    Alpha阶段事后分析
    Alpha阶段项目展示博客
    Alpha阶段测试报告
    Alpha阶段发布说明
    第十次ScrumMeeting博客
    【译】QSerialPort类
    Qt串口通讯
    QDialog设置为无边框
    QBackingStore::flush() called with non-exposed window, behavior is undefined
  • 原文地址:https://www.cnblogs.com/SR-Program/p/14692357.html
Copyright © 2020-2023  润新知