美文网首页Python回忆录
基础篇: 12. Python迭代器和生成器

基础篇: 12. Python迭代器和生成器

作者: 后视镜 | 来源:发表于2019-11-23 11:45 被阅读0次

这里开始是Python开始用到的高级元素了,迭代器和生成器是平常编程用得非常多的,之前其实也有涉及到,但在没有遇到大数据占内存的情况,用不用生成器或者迭代器没有任何区别,特别是在内网测试环境中测试的时候,没有超过百万量的数据,看不出这些的区别,但当数量级一达到了,那就是可大可小的事件了.生成器是迭代器的一种,顾名思义就是不断生成元素,而相对比的就是元素早已生成好,预先占用了大量内存,所以生成器最大的优点就是减少内存占用.

1. 获取一个生成器

列表推导式之前都说过,例子如下:

int_list = [ row for row in xrange(100)]
print(type(int_list))
<type 'list'>

如果把中括号换成小括号:

int_list = (row for row in xrange(100))
print(type(int_list))
<type 'generator'>

上面是其中一种方式,但其实代码都写在一行并不好实现,所以大部分情况都会用到了yield关键字,下面是一个实际的例子,虽然有点复杂,但在实际业务上面是挺有用的一个函数:


def get_part(datas, max_num):
    length = len(datas)
    if length <= max_num:
        yield datas
        return
    beg = 0
    end = beg + max_num
    while beg < length:
        yield datas[beg:end]
        beg = end
        end = beg + max_num

datas = range(10000)
it = get_part(datas, 100)
type(it)
# 输出
generator

这个函数主要用来把列表切分成一段一段返回,一般像批量去获取数据的时候,例如批量获取用户信息,而现在有手上有1万个用户UID,这时候查用户信息的接口只能每次查100个,那么上面的函数就派上用场了.可以看到函数调用后返回的是一个生成器.函数执行到yield的时候就会把数据返回,然后暂停等待下次的取用.每次调用next函数就可以获取到下次的数据,从yield停止的点继续执行.

print(len(it.next()))
100
print(len(it.next()))
100

2. 遍历生成器

当生成器执行完所有逻辑还是继续调用next函数的时候就会抛出StopIteration异常,虽然可以捕捉这个异常来处理,但实际上很多时候都是用for in循环来搭配使用更合适.

datas = range(10000)
for part_data in get_part(datas, 100):
    print(len(part_data))

有很多可以迭代的对象,如以下:

  1. list
  2. dict
  3. set
  4. string
  5. tuple
  6. file

这些都可以用for-in循环来使用.

3. 总结

迭代器和生成器主要是应用得非常广泛,用上生成器的原因是因为可以节省内存,其实类似的也有很多,像读文件的时候并不是把数据都读到内存,而是有个游标记录读到文件的位置.同理数据库查询大量数据的时候,数据库也利用类似的技术,返回一个游标,而不是直接返回全是数据给程序,让程序加载完占用大量的内存.其次利用yield多挖掘一些需要修改的函数,像上文提供的函数也是在实际编程应用得很广,相对应的另一种做法是把数组直接切成了100块,每块100个数据,但问题是如果不是在原数组上面进行修改的话,那么内存的占用量会比之前多很多.所以反复提到用生成器的理由就是节省内存,但有时候为什么又会用到预先加载那种方式?就需要分业务环境来考虑了,预先加载大量数据其实数据量几乎是固定的,而生成器在无法确定数据规模就要考虑使用了.

后视镜 20191123

相关文章

网友评论

    本文标题:基础篇: 12. Python迭代器和生成器

    本文链接:https://www.haomeiwen.com/subject/zpqhwctx.html