假設有一個 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)
複製代碼
固然,我是不推薦這樣寫的。