使用迭代器接收數據並自動中止

假設有一個 Redis 集合,裏面有 N 條數據,你不停從裏面lpop數據,直到某一條數據的值爲'Stop'字符串爲止(已知裏面必有一條數據爲'Stop'字符串,但其位置不知道)。python

這個需求看起來很簡單,因而你馬上就着手寫出了代碼:redis

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列表裏面再返回顯然是不可取的作法。app

好在,這些數據讀取出來之後,會傳給一個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()函數。spa

那麼咱們有沒有辦法把他們區分開來呢?如何讓read_data能返回數據,可是又不會把內存撐爆呢?code

這個時候,咱們就可使用生成器來解決問題:內存

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關鍵字了。string

使用了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)
複製代碼

固然,我是不推薦這樣寫的。

相關文章
相關標籤/搜索