目录
一、生成器 generator
1.1 生成器表达式
1.1.1 表达式一
1.1.2 表达式二
二、可迭代对象、迭代器、生成器三者之间的关系
2.1 定义与特性
2.2 关系与区别
一、生成器 generator
在Python中,生成器(Generators)是一种用于迭代对象的特殊类型函数。
它们允许你生成一个序列的元素,但不像列表(list)那样一次性将所有元素加载到内存中,而是逐个生成元素,从而节省内存空间。
生成器函数使用yield关键字来暂停函数执行并产生一个值,然后在下一次迭代时从上次暂停的位置继续执行。
1.1 生成器表达式
1.1.1 表达式一
在Python中生成器表达式类似于列表推导式,不同的只是列表推导式中的 [ ] 变成了()
eg:
# 列表推导式
li = [i*5 for i in range(5)]
print(li)
# 输出内容:[0, 5, 10, 15, 20]# 生成器表达式
gen = (i*5 for i in range(5))
print(gen)
# 输出内容:<generator object <genexpr> at 0x00000202DB56B648>
那么我们该如何从对象gen中进行取值呢?
这就需要用到上一节课中用到的 next 方法去进行取值
eg:
gen = (i*5 for i in range(5))
# print(gen)
# 输出内容:<generator object <genexpr> at 0x00000202DB56B648>
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
输出结果:
0
5
10
15
20进程已结束,退出代码 0
如果再多运行一个print(next(gen)就会引发StopIteration报错,与迭代器一样
1.1.2 表达式二
生成器函数(重要):Python中,使用了yield关键字的函数就称之为生成器函数
yield的作用:
1.类似return,将指定值或者多个值返回给调用者
2.yield语句一次返回一个结果,在每个结果中间,挂起函数,执行next(),再重新从挂起点继续往下执行,简而言之,yield就是使函数中断,并保存中断的状态
生成器函数在每次调用时,会暂停其执行状态,并在下一次调用时从上次暂停的地方继续执行
基本用法:
在生成器函数中,yield语句用于返回一个值给调用者,并暂停函数的执行,下一次调用生成器的__next__()方法(或在循环中迭代生成器)时,函数会从上次yield语句之后的地方继续执行
eg:
# 定义一个名为simple_generator的生成器函数
def simple_generator():yield 1 # 使用yield返回一个值1给调用者,并在此处暂停函数的执行,挂起状态# 下一次迭代时,函数将从这里恢复运行,但不会重新进入函数体开始处yield 2 # 当函数恢复执行时,继续执行到这里,并返回值2给调用者# 再次暂停函数的执行yield 3 # 同理,函数再次恢复执行时,返回值3给调用者,然后函数再次暂停# 创建一个simple_generator生成器对象
gen = simple_generator()# 使用for循环来迭代生成器对象
for i in gen:print(i) # 在每次迭代中,从生成器中获取一个值(1, 2, 或 3),并打印出来
# 输出:
# 1 # 第一次迭代,打印出生成器返回的第一个值
# 2 # 第二次迭代,打印出生成器返回的第二个值
# 3 # 第三次迭代,打印出生成器返回的第三个值
# 循环结束后,生成器对象已经被耗尽,不会再产生新的值
状态保持:
生成器函数能够保持其局部变量和执行状态,直到下一次被调用
eg:
# 定义一个名为counter的生成器函数
def counter():count = 0 # 初始化计数器变量count为0while True: # 使用无限循环来不断产生新的计数值count += 1 # 每次循环时,将计数器count的值加1yield count # 返回当前的计数值给调用者,并暂停函数的执行# 创建一个counter生成器对象
c = counter()# 使用next()函数调用生成器对象,获取并打印第一个计数值(1)
# 此时,生成器函数执行到第一个yield语句,返回1并暂停
print(next(c)) # 输出: 1# 再次使用next()函数调用生成器对象,获取并打印下一个计数值(2)
# 生成器函数从上次暂停的地方继续执行,执行到下一个yield语句,返回2并再次暂停
print(next(c)) # 输出: 2# 第三次使用next()函数调用生成器对象,获取并打印下一个计数值(3)
# 同理,生成器函数继续执行,返回3并暂停
print(next(c)) # 输出: 3
与for循环结合:
生成器通常与for循环一起使用,因为for循环会自动调用生成器的__next__()方法,直到引发StopIteration异常,这标志着生成器的结束
eg:
# 定义一个简单的生成器函数
def simple_generator():# 使用yield返回一个值1,并在此处暂停函数的执行# 生成器函数的状态会被保存,以便下次从这里继续执行yield 1 # 返回1给调用者,并暂停# 当生成器函数再次被调用时(通过next()或迭代),它会从这里继续执行# 并返回下一个yield语句的值yield 2 # 返回2给调用者,并再次暂停# 同理,这里返回3并暂停,直到生成器被完全迭代完yield 3 # 返回3给调用者,然后生成器函数执行完毕,准备抛出StopIteration# 创建一个生成器对象
gen = simple_generator()# 使用for循环来迭代生成器对象
# for循环会自动调用生成器的__next__()方法,直到捕获到StopIteration异常
for i in gen: # 开始迭代生成器对象# 在每次迭代中,从生成器中获取一个值,并赋值给变量i# 然后执行循环体中的代码print(i) # 打印出从生成器中获取的值# 当生成器被完全迭代完(即所有yield语句都执行过),for循环会自动结束
# 输出将会是:
# 1
# 2
# 3
# 此时,生成器对象已经被耗尽,即它不会再产生新的值了
二、可迭代对象、迭代器、生成器三者之间的关系
2.1 定义与特性
可迭代对象:
定义:实现了__iter__()方法的对象
特性:可以通过iter()函数获取其迭代器,从而进行遍历
示例:列表、元组、字符串、字典、集合等都是可迭代对象
迭代器:
定义:实现了__iter__()和__next__()方法的对象
特性:
1、迭代器对象自身实现了迭代协议,即它既是自己的迭代器
2、可以通过next()函数或迭代器的__next__()方法逐个获取元素,直到抛出StopIteration异常,表示迭代结束
示例:通过调用可迭代对象的__iter__()方法或iter()函数获得的对象就是迭代器
生成器:
定义:一种特殊的迭代器,通过函数中的yield语句来生成值
特性:
1、生成器函数在调用时不会立即执行函数体中的代码,而是返回一个生成器对象
2、生成器对象实现了迭代器的所有方法,包括__iter__()和__next__()
3、每次调用生成器的__next__()方法时,函数会从上次暂停的地方继续执行,直到遇到下一个yield语句或函数结束
4、生成器具有惰性求值的特性,即只在需要时才生成值
示例:包含yield语句的函数就是生成器函数,调用该函数会返回一个生成器对象
2.2 关系与区别
三者之间的关系:
可迭代对象包含迭代器:任何迭代器都是可迭代对象,因为迭代器实现了__iter__()方法(通常返回自身)。但并非所有可迭代对象都是迭代器,因为可迭代对象只需要实现__iter__()方法,而不需要实现__next__()方法
生成器是迭代器的一种特殊形式:生成器自动实现了迭代器协议(即__iter__()和__next__()方法),因此生成器对象既是生成器又是迭代器,
需要注意迭代器并不一定是生成器,它是python提供的通过简便的方法写出迭代器的一种手段
三者之间的区别:
可迭代对象:主要用于表示一个可以遍历的数据集合,但不直接支持通过索引访问元素
迭代器:提供了对可迭代对象进行遍历的统一接口,即__next__()方法。迭代器对象可以在遍历过程中保持内部状态,以便跟踪迭代进度
生成器:通过函数中的yield语句按需生成值,具有惰性求值的特性。生成器在迭代过程中不会一次性生成所有值,而是根据需要逐个生成,从而节省内存空间
今天的分享就到这里了,希望能够对大家有所帮助~