• 技术文章 >头条

    使用迭代器接收数据并自动停止

    silencementsilencement2019-10-25 17:44:34转载1685

    假设有一个 Redis 集合,里面有 N 条数据,你不停从里面lpop数据,直到某一条数据的值为'Stop'字符串为止(已知里面必有一条数据为'Stop'字符串,但其位置不知道)。

    这个需求看起来很简单,于是你立刻就着手写出了代码:

    import redis
    
    client = redis.Redis()
    
    def read_data():
        datas = []
        while True:
            data = client.lpop().decode()
            if data == 'Stop':
                break
            datas.append(data)
        return datas

    现在问题来了,如果 Redis 里面的数据非常多,已经超过了你的内存容量怎么办?数据全部放在datas列表里面再返回显然是不可取的做法。

    好在,这些数据读取出来以后,会传给一个parse函数,并且这个函数是一条一条处理数据的,它处理完成以后,就可以把数据丢弃了。

    于是你可能会这样改写代码:

    import redis
    
    client = redis.Redis()
    
    def read_data():
        while True:
            data = client.lpop().decode()
            if data == 'Stop':
                break
            parse(data)

    但我们知道,在编码规范和软件工程里面,建议一个函数,它应该只做一件事情,而现在read_data()函数却做了两件事情:1. 从 Redis 里面读取数据。2.调用parse()函数。

    那么我们有没有办法把他们区分开来呢?如何让read_data能返回数据,但是又不会把内存撑爆呢?

    这个时候,我们就可以使用生成器来解决问题:

    import redis
    
    client = redis.Redis()
    
    def read_data():
        while True:
            data = client.lpop().decode()
            if data == 'Stop':
                break
            yield data
    
    def parse_data():
        for data in read_data():
            parse(data)

    在这个代码里面,read_data变成了生成器函数,它返回一个生成器,对生成器进行迭代的时候,每次返回一条数据,这一条数据立即传给parse()函数。整个过程源源不断,生生不息。不需要额外创建一个列表用来存放数据。

    那么代码还能不能继续简化呢?此时我们就可以使用iter关键字了。

    使用了iter关键字的效果如下图所示:

    import redis
    
    client = redis.Redis()
    
    def read_data():
        data = client.lpop().decode()
        return data
    
    def parse_data():
        for data in iter(read_data, 'Stop'):
            parse(data)

    其中,read_data现在每运行一次只会返回列表最左边的数据。但是当我们直接使用iter(read_data, 'Stop')的时候,就会得到一个迭代器。对这个迭代器进行迭代,相当于在While True里面不停运行read_data函数,直到某一次迭代的时候,read_data函数返回了Stop,就停止。

    当然如果你想炫技的话,还可以进一步简化:

    import redis
    
    client = redis.Redis()
    
    def parse_data():
        for data in iter(lambda: client.lpop().decode(), 'Stop'):
            parse(data)
    专题推荐:迭代器
    上一篇:1024为什么是程序员日 下一篇:Python核心知识体系的14张思维导图

    相关文章推荐

    • Python3 迭代器与生成器• Python之可迭代对象、迭代器、生成器• python迭代器如何实现

    全部评论我要评论

    © 2021 Python学习网 苏ICP备2021003149号-1

  • 取消发布评论
  • 

    Python学习网