Python 高级特效 - 生成器 ( Generator)

生成器是一种一边循环一边计算的机制,通过列表生成式,可以直接创建一个列表,但是受到内存的限制,列表容量是有限的,当列表元素很大的时候,会很浪费内存空间。所以可以通过生成器 Generator 生成,它的作用相比列表,内存占用少,节约资源。

创建生成器有两种方法,一种是把列表生成式的中括号 [ ] 改成小括号 ( ),一种是函数中包含yield关键字。

1.列表生成式与生成器

可见,列表生成式和生成器的类型分别为 列表 (list) 和 生成器(generator)

javascript 复制代码
print(type([x * 2 for x in range(1,10)]))

print(type((x * 2 for x in range(1, 10))))

对比列表和生成器占用内存的字节,分别为 168 和 96,这好像区别不太大

javascript 复制代码
lst = [x * 2 for x in range(1, 10)]
lst_generator = (x * 2 for x in range(1, 10))

print(lst.__sizeof__())
print(lst_generator.__sizeof__())

当选取的范围增大到10000000后,就有非常明显的差别,可见列表占用内存明显是增大好多倍,和范围值成正比,也就说明列表里的元素越多,占用的内存资源就越大。因此,生成器是有明显的优势。

javascript 复制代码
lst = [x * 2 for x in range(1, 10000000)]
lst_generator = (x * 2 for x in range(1, 10000000))

print(lst.__sizeof__())
print(lst_generator.__sizeof__())

2.函数生成器

假如要读取一个大文本文件,如果使用列表推导式写起来会比较麻烦,也不易于阅读,此时可以用函数来实现。

javascript 复制代码
def read_large_file(file):
    with open(file=file, encoding="utf8") as f:
        lines = f.readlines()
        for line in lines:
            yield line


for i in read_large_file("c:/test_file.txt"):
    print(i)

上一期介绍了递归中 斐波那契数列,也可以用函数生成器的写法实现。yield相当于 return 返回一个值,并且记住这个返回值的位置,下次迭代时,代码从yield的下一条语句开始执行。

javascript 复制代码
def fib(number):
    """number表示最大数量"""
    n, a, b = 0, 0, 1
    while n < number:
        yield b
        a, b = b, a + b
        n = n + 1

for i in fib(10):
    print(i)

那么,生成器怎样去实现取值呢? 生成器也有迭代的属性,也可以理解为它也是迭代器。可以用 next()函数去获取,它是Python内置的函数之一,用于迭代器对象中获取下一个元素。它接受一个迭代器对象作为参数,并返回迭代器对象的下一个数据元素。如果迭代器对象已经到达末尾,则抛出StopIteration异常。

分别取2个值

javascript 复制代码
generator = (x*2 for x in range(1,3))

print(next(generator))
print(next(generator))

当超出 range 取值范围时,会抛出异常

javascript 复制代码
generator = (x*2 for x in range(1,3))

print(next(generator))
print(next(generator))
print(next(generator))

刚才说了,既然生成器也是有迭代属性,那么我们就不需要逐个用 next() 方法去获取值,直接用循环就可以了。

javascript 复制代码
generator = (x*2 for x in range(1,3))

for i in generator:
    print(i)

但作为迭代器的循环和普通列表循环是有区别的,迭代器循环完成遍历后,再运行第二次循环,返回的是空值,而不像列表那样,可以无限执行循环取值。

javascript 复制代码
generator = (x*2 for x in range(1,3))

for i in generator:
    print(i)

for i in generator:
    print(i)

最后简单介绍字典作为迭代器的取值默认属性为 Key, 其中 iter() 函数是可以把有序序列转变为迭代器。

javascript 复制代码
dict = {'one':1, 'two':2, 'three':3}
iter_dict = iter(dict)

for i in iter_dict:
    print(i)

同样,也可以取字典迭代器的 value, 可以通过字典取value,再转换迭代器,这里不再重复演示。

相关推荐
小冷coding6 分钟前
【Java】Dubbo 与 OpenFeign 的核心区别
java·开发语言·dubbo
Coder_Boy_10 分钟前
基于SpringAI的在线考试系统-智能考试系统-学习分析模块
java·开发语言·数据库·spring boot·ddd·tdd
2401_8948281223 分钟前
从原理到实战:随机森林算法全解析(附 Python 完整代码)
开发语言·python·算法·随机森林
B站计算机毕业设计超人23 分钟前
计算机毕业设计Python知识图谱中华古诗词可视化 古诗词情感分析 古诗词智能问答系统 AI大模型自动写诗 大数据毕业设计(源码+LW文档+PPT+讲解)
大数据·人工智能·hadoop·python·机器学习·知识图谱·课程设计
玄同76524 分钟前
Python「焚诀」:吞噬所有语法糖的终极修炼手册
开发语言·数据库·人工智能·python·postgresql·自然语言处理·nlp
johnny23324 分钟前
Python管理工具:包、版本、环境
python
羽翼.玫瑰25 分钟前
关于重装Python失败(本质是未彻底卸载Python)的问题解决方案综述
开发语言·python
cdut_suye25 分钟前
解锁函数的魔力:Python 中的多值传递、灵活参数与无名之美
java·数据库·c++·人工智能·python·机器学习·热榜
木头左1 小时前
指数期权备兑策略量化实现
python
CRMEB系统商城1 小时前
CRMEB多商户系统(PHP)- 移动端二开之基本容器组件使用
运维·开发语言·小程序·php