生成器

生成器

image

1、迭代器与索引取值比较

'''
迭代器取值
    优点:对于不能用索引取值的对象可以采用迭代取值
    缺点:只能依次取值,不能够循环取值
索引取值
    优点:支持循环取值
    缺点:只支持可以用索引取值的对象
'''

image

2、生成器对象

# 生成器对象
# 所谓的生成器对象就是个人自定义的迭代器对象
def fun():
    print('奥利给')
    yield
    print('组装')
    yield
    print('合体')
    yield '铠甲合体'
    print('接受审判吧')
    yield 1, 2, 3


res = fun()  # 函数第一次调用不执行函数代码,只是生成器初始化
print(res)  # <generator object fun at 0x000002358998CBF8>
res.__next__()  # 奥利给
res1 = res.__next__()  # 组装
print(res1)  # None
res2 = res.__next__()  # 合体
print(res2)  # 铠甲合体
res2 = res.__next__()  # 接受审判吧
print(res2)  # (1, 2, 3)
'''
当函数体内有关键字yield时,函数在第一次调用时不执行函数体代码,只是生成器初始化阶段,
关键字yield类似普通函数里的return,在第二次执行双下next方法时才取值,也就是开始执行函数体代码,
且遇到了yield就停在当前阶段,不再运行,当再次调用双下next方法时才会继续往下执行,
且yield后面也可以跟返回内容,yield后面不写默认为None
'''
# yield传值
def index(name):
    while True:
        game = yield
        print(f'{name}正在玩{game}')



res = index('子隽')
print(res.__next__())  # None
res.send('lol')  # 子隽正在玩lol
'''
send方法原理
1、把值传给yield后面的返回值
2、执行res.双下next方法从生成器中取出一个值
'''
# 关键字yield和关键字return的比较
'''
return:1、函数体代码一旦遇到return,函数立即结束,
       2、return后面可以跟返回值,且接收多个元素时,会组成元组的形式返回
yield: 1、函数体代码一旦遇到yield,会立即停留在当前位置,函数不会结束
       2、yield后面可以跟返回值,且接收多个元素时,会组成元组的形式返回
       3、yield支持用send方法传值
'''

image

3、自定义range迭代器

# range方法可以传值,且每次传值的数量不固定,一共可以有三个参数
def my_range(start, end=None, step=1):  # range的三个参数是起始位置,结束位置,步长
    # 当我们只输入一个数值时,这时候默认为初始值,我们把初始值赋值给end,同时,开始值为0
    # 且我们只写一个值时,end默认为None
    # 然后对end是否存在进行判断
    if not end:
        end = start
        start = 0
    # 利用while循环判断起始位置和结束位置的数值大小
    while start < end:
        # 如果条件成立,则返回初始值
        yield start
        # start的值每次加1,当我们需要填入步长时,start的值每次加一个步长,这里可以把步长设置一个默认值为1
        # 当我们不写步长时,默认步长为1
        start += step


# 先调用函数,开始生成器的初始阶段
res = my_range(10)
# 再利用for循环取值
# 再打印之前我们定义一个空列表用来存放我们每次取出的值
new_list = []
for i in my_range(1, 10, 2):
    # 把每次取出的值追加到列表里
    new_list.append(i)
# 把添加完的列表打印出来
print(new_list)  # [1, 3, 5, 7, 9]
'''
再来对比一下直接用range取值
'''
new_list1 = []
for i in range(1, 10, 2):
    new_list1.append(i)
print(new_list1)  # [1, 3, 5, 7, 9]
# 到这里我们自定义的range迭代器就成功实现了

image

4、生成器表达式

# 所谓的生成器表达式也就是快速生成一个生成器对象的方式
# 语法结构
list1 = [1, 2, 3, 4, 5]
res = (i + 1 for i in list1)
print(res)  # <generator object <genexpr> at 0x000001CC81182D58>
'''
从上面的情况可以看出来,我们在定义生成器的阶段是不执行任何操作的,只是生成了一个生成器对象
'''
list2 = [1, 2, 3, 4, 5]
res = (i + 1 for i in list2)
print(res.__next__())  # 2
print(res.__next__())  # 3

'''
结合上述情况可以得出一个结论:
生成器表达式在定义阶段不会执行表达式中的代码,只有在我们从中取值调用的时候才会开始执行
'''

'''
迭代器对象,生成器对象在这里我们可以看成是一个工厂,只有在我们需要某个零件时
,也即是当我们在索要数据时,才会反馈给我们结果
而这样做的目的是为了节省空间,
'''

image

5、生成器笔试题

# 求和
def add(n, i):
    return n + i
# 调用之前是函数 调用之后是生成器
def test():
    for i in range(4):
        yield i
g = test()  # 初始化生成器对象
for n in [1, 10]:
    g = (add(n, i) for i in g)
    """
    第一次for循环
        g = (add(n, i) for i in g)
        在我们第一循环时,只是进行的生成器定义阶段,不会传值,且不会从中取值
    第二次for循环
        g = (add(10, i) for i in (add(10, i) for i in g))
        当我们第二次循环时,n的值变成了10,且第一次循环的g变成了第一次循环的生成器表达式,最内部的g就是我们的test生成器,从内到外一步步推
        就能得到我们想要的答案
    """
res = list(g)
print(res)  # [20, 21, 22, 23]

#A. res=[10,11,12,13]
#B. res=[11,12,13,14]
#C. res=[20,21,22,23]
#D. res=[21,22,23,24]

image

posted @ 2021-11-22 19:53  PyLy  阅读(247)  评论(0)    收藏  举报

念两句诗

入我相思门,知我相思苦,长相思兮长相忆,短相思兮无穷极。
【唐代】李白