Python 的generator
通常我们会有一个函数get_x_data来提供某些数据,然后另外的一个函数handle_x_data遍历那些数据进行处理。这时就会出现一个问题, 如果get_x_data 返回大量数据,这些数据就会占用很多内存,同时程序又会停在get_x_data 上很长时间。那么能不能让get_x_data 找到一个值,就传递给handle_x_data 处理,处理完了,get_x_data 把下一个值交给handle_x_data 进行处理,就这样一个个的处理,既避免了内存的浪费,也避免了程序在get_x_data 上停留太多时间。例如:
for i in get_x_data():
handle_x_data(i)
这里的get_x_data() 并没有立即返回所有data, 而是每次返回一个,待handld_x_data() 处理完这个data, 再返回下一个。
在Python 中很容易很优雅地做到!
Python 中有个range 函数,在Python 2 中,range() 会返回一个list, 会将这个list 生成好,放入内存。 而如果想使用逐个返回的方法,就需要使用xrange. Python 3 中已经没有xrange, 而range 则返回一个generator 而不再是一个list.
模拟xrange:
def xrange(n):
i = 0
while i < n:
yield i
i += 1
for it in xrange(10):
print(it)
xrange 每次执行完yield i, i 就会被传递到it 中, 而停止在下一次yield 处,直到for 语句向range 要下一个值。
实际中的应用:
elasticsearch 为了避免客户端一次请求太多数据而占用太多客户端内存的问题,它提供了另外一种途径,根据客户端的查询条件,为客户端生成一个scroll id。 然后客户端根据这个scoll id 多次小批量地请求所需要的data. 所以如果应用原生的elasticsearch api 就比较麻烦,需要先获得scroll id, 然后再根据scroll id 多次请求。
我们可以通过yield 很好的包装这种请求:
def get_xxxx(self, query):
"""
return a generator, you can query the data in the way of
for i in yyyy.get_xxx(query):
print(i)
"""
result = []
scroll_id = self.__scroll_id(query) // get scroll id
result = self.__get_scroll_data(scroll_id) // get data from scroll id, result is a list
while result: // result is not empty
yield result.pop()
if not result: // result is empty, fetch next batch of data
result = self.__get_scroll_data(scroll_id)

浙公网安备 33010602011771号