python迭代器和生成器更深入了解

本文深入探讨Python中的迭代器和生成器概念,对比其与传统循环的区别,通过实例展示生成器如何节省内存并提升效率,适用于大规模数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在初次接触python的时候,我们有时会遇到 for i in [1, 2, 3, 5, 8]: print(i)这样类似的语句,比起java和c++的for(int i=0; i<n; i++) printf("%d\n", a[i])这样的语句,简洁了许多。

在python中,一切接对象,对象的抽象就是类,对象的集合就是容器。
列表、元组、字典、集合都是容器。所有的容器都是可迭代的,这里的迭代,和枚举不同。迭代时,你并不需要知道里面有多少元素。
迭代器提供了一个next方法,调用这个方法后,得到容器的下一个对象,迭代完后,会报StopIteration错误。可迭代对象,通过iter()函数返回一个迭代器,再通过next() 可实现遍历,for in 语句将这个过程隐式化。
可迭代类型:

  • 字符串
  • 列表
  • 元组
  • 集合
  • 字典

那么,生成器又是什么?
通俗理解,生成器是懒人版本的迭代器,它的好处有许多,请看如下示例:

import os
import psutil

#显示当前python程序占用内存大小
def show_memory_info(hint):
    pid = os.getpid()
    p = psutil.Process(pid)

    info = p.memory_full_info()
    memory = info.uss/1024./1024
    print('{}memory used:{} MB'.format(hint,memory))


def test_iteration():
    show_memory_info('initing iterator')
    list1 = [i for i in range(10000000)]
    show_memory_info('after iterator initiated')
    print(sum(list1))
    show_memory_info('after sum called')

def test_generation():
    show_memory_info('initing iterator')
    list2 = (i for i in range(10000000))
    show_memory_info('after iterator initiated')
    print(sum(list2))
    show_memory_info('after sum called')

test_iteration()
test_generation()

在这里插入图片描述

使用迭代器很简单,如果迭代器中的元素太多,内存不够的话会报OOM错误。
生成器便不一样了,它并不会像迭代器一样占用巨量内存,它只有在被使用时才会被调用,在你调用next()时才会生成下一个变量。元素非常多时,生成器所用的时间和内存都比迭代器少上许多。

下面举一个例子:
给定一个指定数字,求这个数字在list中的位置
常规做法:

def find_index(alist, target):
    result = []
    for i, num in enumerate(alist):
        if num == target:
            result.append(i)
    return result

print(find_index([3, 2, 56, 2, 6, 35, 2, 63], 2))

#>>>[1, 3, 6]

上面是常规做法,枚举。下面使用迭代器和生成器,代码如下:

def index_generator(alist, target):
    for i, num in enumerate(alist):
        if num == target:
            yield i

print(list(index_generator([3, 2, 56, 2, 6, 35, 2, 63], 2))) #必须转换成列表后才能输出结果

#>>> [1, 3, 6]

python讲究的是用更少更清晰的代码实现相同功能,生成器便能很好符合这个要求。

再来个例子:
给定两个序列,判断第一个是不是第二个的子序列,字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。

这个问题的常规解法为贪心算法,使用两个指针指向列表的开始,对第二个序列一路扫过去,如果某个数字和第一个指针一样,就把第一个指针前进一步,如此判断。

如果使用迭代器和生成器呢?

def judge(a, b):
    b = iter(b)
    return all(i in b for i in a)

print(judge([1,3,2], [1,2,3,4,5]))
print(judge([1,4,5], [1,2,3,4,5]))

# True
# False

总结:

  • 容器是可迭代对象,迭代器可以通过next()函数来得到下一个元素,从而支持遍历
  • 生成器是一种特殊的迭代器,合理使用生成器,可以降低内存占用、优化程序结构、提高运行速度
  • 生成器是实现协程的一种重要方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值