假设有一个 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)
复制代码
固然,我是不推荐这样写的。