Python 高级特性(4)- 生成器 generator

简介: Python 高级特性(4)- 生成器 generator

列表生成式


通过上一篇介绍 列表生成式文章可以知道,它可以快速创建我们需要的列表

 

局限性

  • 受内存限制,列表生成式创建的列表的容量肯定有限的
  • 不仅占用很大的存储空间,如果我们仅仅需要访问前几个元素,那后面绝大多数元素占用的空间都白白浪费了

 

什么是生成器


  • 若列表元素可以按照某种算法算出来,就可以在循环的过程中不断推算出后续需要用的元素,而不必创建完整的 list,从而节省大量的空间
  • 边循环边计算的机制,叫生成器(generator)

 

最简单的生成器


L = [x * x for x in range(10)]
print(L)
print(type(L))
L = (x * x for x in range(10))
print(L)
print(type(L))
# 输出结果
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<class 'list'>
<generator object <genexpr> at 0x000001D607541EB8>
<class 'generator'>


只要把一个列表生成式的 [] 改成 () ,就创建了一个 generator

 

如何打印生成器每个元素


直接简单 for 循环

L2 = (x * x for x in range(10))
for i in L2:
    print(i)


next() 方法

可以获取 generator 的下一个元素

基本不会使用这个

L2 = (x for x in range(10))
print(next(L2))
print(next(L2))
print(next(L2))
print(next(L2))
print(next(L2))
print(next(L2))
# 输出结果
0
1
2
3
4
5


还有另一个方法 .__next()__

L2 = (x for x in range(10))
print(L2.__next__())
print(L2.__next__())
print(L2.__next__())
print(L2.__next__())
print(L2.__next__())
print(L2.__next__())
# 输出结果
0
1
2
3
4
5


生成器的迭代原理


generator 能够迭代的关键就是 next() 方法,通过重复调用 next() 方法,直到捕获一个异常

 

yield 函数


  • 带有 yield的函数不再是一个普通函数,而是一个生成器 generator
  • yield 相当于 return 返回一个值,并且记住这个返回值的位置,下次迭代时,代码会从 yield 的下一条语句开始执行,直到函数结束或遇到下一个 yield

 

普通的斐波拉契数列


1, 1, 2, 3, 5, 8, 13, 21, 34, ...,除第一个和第二个数外,任意一个数都可由前两个数相加得到

# 斐波拉契数列
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
fib(8)
# 输出结果
1
1
2
3
5
8
13
21


它和生成器很像,知道第一个元素值,就可以推算后面的任意个元素了

 

是用 yield 的斐波拉契数列


def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
fib(8)
print(fib(8))
# 输出结果
1
1
2
3
5
8
13
21
<generator object fib at 0x00000246A5001EB8>


生成器的执行流程


函数是顺序执行,遇到 return 或者最后一行执行完就返回

 

而生成器的执行流程是

  • 每次调用 next() 或 for 循环的时候执行,遇到 yield 就返回
  • 一个生成器里面可以有多个 yield
  • 再次执行时从上次返回的 yield 语句处继续执行


# 执行流程
def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield 3
    print('step 3')
    yield 5
L = odd()
for i in L:
    print(i)
# 输出结果
step 1
1
step 2
3
step 3
5


生成器的工作原理


  • 它是在 for 循环过程中不断计算下一个元素,并在适当的条件结束 for 循环
  • 对于函数改成的 generator 来说,,遇到 return 语句或者执行到函数最后一行时,就是结束 generator 的指令,for 循环随之结束

 

生成器的优点


在不牺牲过多速度情况下,释放了内存,支持大数据量的操作

 

不使用生成器下的代码

from tqdm import tqdm
a = []
for i in tqdm(range(10000000)):
    temp = ['你好'] * 2000
    a.append(temp)
for ele in a:
    continue


image.png


可以看到开始运行大数据量循环代码后,内存暴增,并且占满了电脑所有内存,很明显这是不合理且不可接受的!

 

使用生成器的代码

def test():
    for i in tqdm(range(10000000)):
        temp = ['你好'] * 2000
        yield temp
a = test()
for ele in a:
    continue


image.png


内存丝滑的很,奈斯!

 

生成器的应用场景

当然就是需要处理大数据量的场景了,比如一个文件有几百万行数据,或者有几百万个文件需要分别读取处理

 

相关文章
|
1月前
|
安全 数据处理 索引
深入探讨 Python 列表与元组:操作技巧、性能特性与适用场景
Python 列表和元组是两种强大且常用的数据结构,各自具有独特的特性和适用场景。通过对它们的深入理解和熟练应用,可以显著提高编程效率和代码质量。无论是在数据处理、函数参数传递还是多线程环境中,合理选择和使用列表与元组都能够使得代码更加简洁、高效和安全。
49 9
|
3月前
|
Python
闭包(Closure)是**Python中的一种高级特性
闭包(Closure)是**Python中的一种高级特性
74 8
|
4月前
|
大数据 数据处理 开发者
Python中的迭代器和生成器:不仅仅是语法糖####
本文探讨了Python中迭代器和生成器的深层价值,它们不仅简化代码、提升性能,还促进了函数式编程风格。通过具体示例,揭示了这些工具在处理大数据、惰性求值及资源管理等方面的优势。 ####
|
5月前
|
存储 索引 Python
Python生成器、装饰器、异常(2)
【10月更文挑战第16天】
80 1
Python生成器、装饰器、异常(2)
|
5月前
|
Python
Python生成器、装饰器、异常
【10月更文挑战第15天】
44 2
|
4月前
|
JavaScript 前端开发 算法
python中的列表生成式和生成器
欢迎来到瑞雨溪的博客,这里是一位热爱JavaScript和Vue的大一学生的天地。通过自学前端技术2年半,现正向全栈开发迈进。如果你从我的文章中受益,欢迎关注,我将持续更新高质量内容,你的支持是我前进的动力!🎉🎉🎉
63 0
|
5月前
|
存储 数据处理 Python
深入解析Python中的生成器:效率与性能的双重提升
生成器不仅是Python中的一个高级特性,它们是构建高效、内存友好型应用程序的基石。本文将深入探讨生成器的内部机制,揭示它们如何通过惰性计算和迭代器协议提高数据处理的效率。
|
5月前
|
传感器 大数据 数据处理
深入理解Python中的生成器:用法及应用场景
【10月更文挑战第7天】深入理解Python中的生成器:用法及应用场景
194 1
|
5月前
|
存储 大数据 数据处理
Python 中的列表推导式与生成器:特性、用途与区别
Python 中的列表推导式与生成器:特性、用途与区别
58 2
|
4月前
|
存储 程序员 数据处理
深入理解Python中的生成器与迭代器###
本文将探讨Python中生成器与迭代器的核心概念,通过对比分析二者的异同,结合具体代码示例,揭示它们在提高程序效率、优化内存使用方面的独特优势。生成器作为迭代器的一种特殊形式,其惰性求值的特性使其在处理大数据流时表现尤为出色。掌握生成器与迭代器的灵活运用,对于提升Python编程技能及解决复杂问题具有重要意义。 ###