个人主页:丷从心
系列专栏:Python基础
学习指南:Python学习指南
Python
中,使用生成器可以很方便地支持迭代器协议def
定义,但不是通过return
返回,而是通过yield
一次返回一个结果,在每个结果之间挂起和继续它们的状态,来实现迭代器协议yield
本质上是一个语法糖,内部是一个状态机,维护着挂起和继续的状态,从而支持迭代器协议def my_range(n):
i = 0
while i < n:
yield i
i += 1
my_range = my_range(3)
print(my_range)
print(next(my_range))
print(next(my_range))
print(next(my_range))
<generator object my_range at 0x0000019CE75804A0>
0
1
2
my_range()
__iter__()
方法和__next__()
方法,dir()
函数可以获取一个对象的所有属性和方法,可以使用dir()
函数查看生成器对象的属性和方法def my_range(n):
i = 0
while i < n:
yield i
i += 1
my_range = my_range(3)
print(dir(my_range))
print('__iter__' in dir(my_range))
print('__next__' in dir(my_range))
['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']
True
True
def my_range(n):
print('开始迭代...')
print('-' * 10)
i = 0
while i < n:
print('迭代中...')
yield i
print('-' * 10)
i += 1
print('迭代结束')
gen_obj = my_range(3)
print(next(gen_obj))
print(next(gen_obj))
print(next(gen_obj))
开始迭代...
----------
迭代中...
0
----------
迭代结束
迭代中...
1
----------
迭代结束
迭代中...
2
next()
方法的时候,生成器函数才开始运行,运行到yield
语句处停止,并将i
作为返回值返回,执行过程为图中的①②next()
方法的时候,生成器函数从上一次停止的地方,也就是yield
语句处继续运行,直到再次运行到yield
语句处停止, 并将i
作为返回值返回,执行过程为图中的③④②yield
语句,就抛出StopIteration
异常,生成器在当前yield
语句处停止,不再执行③④②过程nums = [i for i in range(10) if i % 2]
print(nums)
[1, 3, 5, 7, 9]
()
括起来的gen_obj = (i for i in range(10) if i % 2)
print(gen_obj)
<generator object <genexpr> at 0x000001D6DC1E04A0>
yield
)出一个值来,实现了惰性加载(懒加载),只有在被迭代时才被赋值,并覆盖上一个值,所以在序列较长的情况下,使用生成器会优化内存send()
方法和close()
方法send()
方法和close
方法send()
方法Python 2.5
中,yield
语句变成了yield
表达式,也就是说yield
可以有一个值,而这个值就是send()
方法的参数,通过调用send()
方法将值传递给yield
,而send()
的返回值为yield
返回的值,所以send(None)
和next()
是等效的send()
传入非None
值前,生成器必须处于挂起状态,否则将抛出异常,也就是说,第一次运行生成器时,只能使用next()
或send(None)
,因为没有yield
来接收这个值def my_range(n):
i = 0
while i < n:
var = yield i
print(f'var 的值为 {var}')
i += 1
my_range = my_range(3)
print(my_range.send(None))
print(my_range.send('hello'))
print(my_range.send('world'))
0
var 的值为 hello
1
var 的值为 world
2
close()
方法close()
方法用于关闭生成器,对关闭后的生成器再次调用next()
或send()
将抛出StopIteration
异常def my_range(n):
i = 0
while i < n:
var = yield i
print(f'var 的值为 {var}')
i += 1
my_range = my_range(3)
print(my_range.send(None))
print(my_range.send('hello'))
my_range.close()
print(my_range.send('world'))
0
var 的值为 hello
1
Traceback (most recent call last):
File "C:/Users/FOLLOW_MY_HEART/Desktop/Python基础/【Python基础】生成器/test.py", line 18, in <module>
print(my_range.send('world'))
StopIteration