生成器
- 介绍:根据程序员指定的规则循环生成数据,当条件不成立时则生成数据结束。数据不是一次性全部生产出来,而是使用一个再生成一个,可以节约大量的内存。
- 创建方式:
- 生成器推导式;
-
yield
关键字
生成器推导式
- 与列表推导式类似,只不过生成器推导式使用的是小括号
()
。具体区别可以查看“Python基础学习笔记”中的“列表解析式和生成表达式(列表推导式)”。 -
for
循环内部自动处理了停止迭代异常,使用起来更加方便,推荐大家使用。
iter1 = [i for i in range(100000)] # 列表推导式
iter2 = (i for i in range(100000)) # 生成器推导式
# iter1占了824440字节 iter2占了96字节 (单位应该是字节)
print(f"列表推导式生成的数据占用内容空间的大小:{iter1.__sizeof__()}\n"
f"生成推导式生成的诗句占用内存空间的大小:{iter2.__sizeof__()}")
print(len(iter1)) # 长度是100000
print(iter2) # 输出的是生成器对象的内存地址
for i in iter2: # 方式一:for循环可以遍历输出生成器的内容
print(i)
if i == 100:
break
yield
关键字(生成器函数)
- 只要在函数中使用了
yield
关键字的函数就被称为生成器(generator
)。 - 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器:调用一个生成器函数,返回的是一个迭代器对象。
- 代码说明:
- 在调用生成器运行的过程中,每次遇到
yield
时函数会
- 暂停
- 保存当前所有的运行信息
- 返回
yield
的值,并在下一次执行next()
方法时 - 从当前位置继续运行。
- 生成器如果把输出成完成,再次获取生成器中的下一个数据会抛出一个
StopIteration
异常,表示停止迭代异常。 -
while
循环内没有处理异常操作,需要手动添加处理异常操作
def iter_yield():
print("-" * 20)
yield 1
print("-" * 20)
yield 2
print("-" * 20)
yield 3
i_y = iter_yield()
# 想要运行生成器函数中代码需要 for 或者 next 调用
# 值 = next(生成器对象):执行一次生成器对象取出一个值,类似于for循环的底层
while True:
try:
i = next(i_y)
print(i)
except StopIteration as err:
break
# sys.exit()
生成器应用场景
- 通常用
yield
代替return
:当函数需要连续弹出多个值,并且每次只弹出一个值的时候使用,因为return
会直接终止程序,而yield
不会。 - 注意:
yield
返回的值被用一次后指针被移到了最后面。 - 需求:
- 数学中有个著名的费波拉契数列(
Gibonacci
),数列中第一个数为0,第二个数为1,其后每一个数都是由前两个数相加得到:0 1 1 2 3 5 8 13 21 34 … - 现在我们使用生成器来实现这个费波拉契数列,每次取值都通过算法来生成下一个数据,生成器每次只调用一个数据,可以节省大量的内存。
# 生成器函数 - 斐波那契
def fibonacci(n):
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
# f 是一个迭代器,由生成器返回生成
f = fibonacci(10)
print(f)
# print(tuple(f)) # 可以直接转成元组
# print(list(f)) # 可以直接转成元组
for value in f:
print(value, end=' ')
print(list(f)) // 使用一次后指针被