生成器对象(自定义迭代器)

本质还是一个迭代器,只不过是自己定义迭代器,自己写来的

使用了 yield 的函数被称为生成器,跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

内部也还是只有__iter__和__next__方法
# 生成器对象也是节省存储空间的,特性与迭代器对象一致
'''
当函数体代码中含有yield关键字
	第一次调用函数并不会执行函数体代码
	而是将函数变成了生成器
'''
表现形式:
def index():
    print('111')
    yield 123
    print('222')
    yield 666
print(index)  # <function index at 0x000001B29A8CC158>
# 没有调用之前就是一个普通的函数
# 加括号调用并接收结果:不执行代码 而是变成是生成器对象(迭代器)
res = index()
print(res)  # <generator object index at 0x0000020ABA02FEB8>
# 变成生成器对象之后调用__next__就会开始执行函数体代码
print(res.__next__())
# 111
# 123
print(res.__next__())
# 222
# 666
print(res.__next__())  # 报错
'''
如果函数体代码中含有多个yield关键字,执行一次__next__返回后面的值并且让代码停留在yield位置
再次执行__next__基于上次的位置继续往后执行到写一个yield关键字处
如果没有了 再执行也会报错    StopIteration
'''

自定义range方法

# range方法其实是一个可迭代对象
for i in range(1,10)
print(i)
'''通过生成器模拟range方法'''
def my_range(start, end=None, stop=1):  # 起始位置,终止位置,步长
    if not end:  # 如果没有给终止位置传值,则将起始位置的值给终止位置
        end = start
        start = 0  # 再将起始位置赋值为0
    while start < end:  # 循环判断
       yield start  # 输出start
       start += stop  # 相当于步长

for i in my_range(1,100,2):
    print(i)

yield关键字作用

1.在函数体代码中出现,可以将函数变成生成器
2.再执行过程中,可以将后面的值返回出去,类似于return
3.还可以暂停住代码的运行
4.还可以接受外界的传值

send 关键字

# send关键字可以给yield传值,并且自动调用一次__next__方法
def my_func(name):
    print(f'{name}')
    while True:
        s = yield
        print(f'{name}和{s}')

res = my_func('tuzi')
res.__next__()  # tuzi
res.__next__()  # tuzi和None
res.send('jason')  # tuzi和jason
# 可以给yield传值 并且自动调用一次__next__方法

生成器表达式

# 也是为了节省存储空间,主要用于后期做代码优化
语法结构:
	res = (变量名 for 变量名 in 循环体代码)
"""
生成器内部的代码只有在调用__next__迭代取值的时候才会执行
"""