生成器


什么是生成器

  生成器就是自定义迭代器

生成器语法

def my_ge():
    print('first')
    yield 123,222,333

  注:生成器在定义阶段就是普通的函数

关于yield关键字

  1、当函数体内含义yield关键字,那么第一次在调用函数的时候,并不会调用函数体代码,而是将函数变成了生成器(迭代器)

def my_ge():
    print('first')
    yield 123,222,333
    print('second')
    yield 456,444,555
res = my_ge()
ret = res.__next__()  # 每执行一个__next__代码往下运行到yield停止 返回后面的数据
print(ret)
ret1 = res.__next__()  # 再次执行__next__接着上次停止的地方继续往后 遇到yield再停止
print(ret1)
# 结果 
# first
# (123, 222, 333)
# second
# (456, 444, 555)

  2、yield取值

def eat(name):
    print('%s 准备吃饭!!!'%name)
    while True:
        food = yield
        print('%s 正在吃 %s' % (name, food))
res = eat('tony')  # 并不会执行代码 而是转换成生成器
res.__next__()
res.send('包子')
res.send('面条')
# tony 准备吃饭!!!
# tony 正在吃 包子
# tony 正在吃 面条

  3、yield与return对比

    yield

      1、可以返回值(支持多个并且组织成元组)

      2、函数体代码遇到yield不会结束而是”停住“

      3、yield可以将函数变成生成器,并且还支持外界传值

    return

      1、可以返回值(支持多个并且组织成元组)

      2、函数体代码遇到return直接结束

生成器表达式

  1、生成器表达式和列表生成式很相似。生成器表达式是用小括号括起来的。列表生成式是中括号括起来的

l = [11, 22, 33, 44, 55, 66, 77, 88, 99]
# 列表生成式
res = [i+1 for i in l if i!=44]
print(res)
# 生成器表达式
res1 = (i+1 for i in l if i!=44)

  2、生成器表达式内部的代码只有在迭代取值的时候才会执行;迭代器对象、生成器对象,我们都可以看成是“工厂”,只有当我们所要数据的时候工厂才会加工出“数据”,主要都是为了节省空间。

  3、练习题

# 求和
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(1, i) for i in g)
    第二次for循环
        g = (add(10, i) for i in (add(10, i) for i in g))
    """
res = list(g)
print(res)

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

自定义range方法

def my_range(start, stop=None, step=1):
    if not stop:
        stop = start
        start = 0
    while start < stop:
        yield start
        start += step
#  第一种
res = my_range(1,10,2)
for i in res:
    print(i)
# 第二种
res = my_range(10)
for i in res:
    print(i)
# 第三种
res = my_range(1,10)
for i in res:
    print(i)

迭代取值与索引取值对比

  1、迭代取值

    优点:不依赖于索引的一种通用取值方法

    缺点:取值的顺序永远都是固定的从左往右,无法重复取值

  2、索引取值

    优点:可以重复取值

    缺点:需要提供有序容器类型才可取值(不是一种通用方式)

相关