python生成器有几种写法,python生成器的作用

这篇文章主要介绍了python生成器有几种写法,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。

1. 生成器创建方式一

list 容器为例,在使用该容器迭代一组数据时,必须事先将所有数据存储到容器中,才能开始迭代;而生成器却不同,它可以实现在迭代的同时生成元素。并不会一次性生成它们,而是什么时候需要,才什么时候生成python画心的代码演示

在生成列表或者元组的时候,我们常常使用生成器。

① 在列表中,直接生成新的列表

ls = [i for i in range(1, 10) if i % 2 == 0]
print(type(ls))

执行结果:
在这里插入图片描述

② 在元组中,生成的则为 generator 类型

l = (i for i in range(1, 10000000) if i % 2 == 0) # 这里只是创建了一个生成器,并不会执行输出里面的元素

print(type(l))

执行结果:
在这里插入图片描述

对于 generator 类型,生成器本身通过遍历指针获得新元组,当生成器完成后指针也就失效,这时再通过该生成器则不会有结果

l = (i for i in range(1, 10) if i % 2 == 0)

print("生成器在第一次生成元组时:", tuple(l))
print("当再此利用其生成元组时", tuple(l))

执行结果:
在这里插入图片描述
可见,生成器仅在第一次遍历时生效。

③ 探究生成器的工作机制

l = (i for i in range(1, 10) if i % 2 == 0)

print(next(l))
print(next(l))
print(l.__next__())
print(l.__next__())
print(l.__next__())

执行结果: 当指针到达末尾时,next 返回的数据也就不存在了,这时编译器便会报错。这里的 next()生成器.__next()__没有区别,效果一样
在这里插入图片描述

2. 生成器的创建方式二

创建生成器的步骤:

  1. 定义一个以 yield 关键字标识返回值的函数;
  2. 调用刚刚创建的函数,即可创建一个生成器。
def intNum():
    print("开始执行")
    for i in range(5):
        yield i
        print("继续执行")
num = intNum()

由此,我们就成功创建了一个 num 生成器对象。显然,和普通函数不同,intNum() 函数的返回值用的是 yield 关键字,而不是 return 关键字,此类函数又成为生成器函数

return 相比,yield 除了可以返回相应的值,还有一个更重要的功能,即每当程序执行完该语句时,程序就会暂停执行。不仅如此,即便调用生成器函数,Python 解释器也不会执行函数中的代码,它只会返回一个生成器(对象)。

要想使生成器函数得以执行,或者想使执行完 yield 语句暂停的程序得以继续执行,有以下 2 种方式:

  • 生成器.__next__() 方法 或 Pyhon 内置的 next() 方法;
  • 通过 for 循环遍历生成器。
# 创建生成器函数
def intNum():
    print("开始执行")
    for i in range(5):
        yield i
        print("继续执行")

# 调用生成器函数并然会生成器对象
num = intNum()

#调用 next() 内置函数
print(next(num))

#调用 __next__() 方法
print(num.__next__())

#通过for循环遍历生成器
for i in num:
    print(i)

执行结果:
在这里插入图片描述
执行流程:

  1. 首先,在创建有 num 生成器的前提下,通过其调用 next() 内置函数,会使 Python 解释器开始执行 intNum() 生成器函数中的代码,因此会输出“开始执行”,程序会一直执行到 yield i,而此时的 i == 0,因此 Python 解释器输出 “0”。由于受到 yield 的影响,程序会在此处暂停。

  2. 然后,我们使用 num 生成器调用 __next__() 方法,该方法的作用和 next() 函数完全相同(事实上,next() 函数的底层执行的也是 __next__() 方法),它会是程序继续执行,即输出 “继续执行”,程序又会执行到 yield i,此时 i==1,因此输出 “1”,然后程序暂停。

  3. 最后,我们使用 for 循环遍历 num 生成器,之所以能这么做,是因为 for 循环底层会不断地调用 next() 函数,使暂停的程序继续执行,因此会输出后续的结果。

除此之外,还可以使用 list() 函数和 tuple() 函数,直接将生成器能生成的所有值存储成列表或者元组的形式。

# 创建生成器函数
def intNum():
    print("开始执行")
    for i in range(5):
        yield i
        print("继续执行")

# 调用生成器函数并然会生成器对象
num = intNum()

print(list(num))

执行结果:
在这里插入图片描述

# 创建生成器函数
def intNum():
    print("开始执行")
    for i in range(5):
        yield i
        print("继续执行")

# 调用生成器函数并然会生成器对象
num = intNum()
print(tuple(num))

执行结果:
在这里插入图片描述
通过输出结果可以判断出,list()tuple() 底层实现和 for 循环的遍历过程是类似的。

深入剖析生成器

yied, 可以去阻断当前的函数执行, 然后, 当使用 next() 函数, 或者, __next__(), 都会让函数继续执行, 然后, 当执行到下一个 yield 语句的时候, 又会被暂停

def test():
    print("xxx")
    yield 1
    print("a")

    yield 2
    print("b")

    yield 3
    print("c")

    yield 4
    print("d")

    yield 5
    print("e")

g = test()
print(g)

print(next(g))
print(next(g))

执行过程: 调用第一个 next(g) ,会执行 print("xxx"),并在遇到 yield 1 后暂停执行,返回 1,由于执行了 print(next(g)) ,所以 1 被打印了出来,并保存执行状态,在执行第二个 next(g) 时,执行 print("a") 再遇到 yield 2,并返回 2,同时由于 print(next(g)) ,所以 2 被打印了出来,后续同理

再看一个案例:

def test():
    for i in range(1, 9):
        yield i

g = test()
print(g)

next(g)
print(next(g))

执行结果:
在这里插入图片描述
执行流程: 定义好生成器函数后,通过 g = test() 得到一个生成器对象,执行 next(g) 时,会进入第一个循环,此时 i == 1,所以 yield i 会返回 1,但是并为通过 print 函数打印,然后执行 print(next(g)),此时 i == 2, 在执行到 yield i 时,返回 2, 并通过 print 函数打印出

3. send 方法

send 不仅具有 next() 功能,还能够给上一个 yield 语句传值

def test():
    # print("xxx")
    res1 = yield 1 
    print(res1)

    res2 = yield 2
    print(res2)

g = test()

print(next(g))

print(g.__next__())

执行结果:
在这里插入图片描述
第一个 1 是通过 yield 1 返回后再通过 print(next(g)) 打印出来,此时 res1 接收 yield 1 的赋值,为 None,在下次执行时,优先打印出 None

def test():
    # print("xxx")
    res1 = yield 1 # "ooo"
    print(res1)

    res2 = yield 2
    print(res2)

g = test()


print(g.__next__())
print(g.send("ooo"))

执行结果:
在这里插入图片描述
执行流程:print(g.__next__()),会触发第一个 yield 语句,并打印返回的 1 ,然后再执行 g.send("ooo"),此时给上一个 yield 语句传值,并复制给 res1 ,由于自身具备 next() 函数功能,所以触发下一个 yield 语句执行,打印出了 ooo,以及返回的值 2

注: 再没有优先利用 next 触发 yield 语句, send 就不能给上一个 yield 赋值,此时,只能传入None,即只能执行 send(None)

4. close 方法

def test():
    yield 1
    print("a")

    yield 2
    print("b")

    yield 3
    print("c")

    return 10



g = test()

print(g.__next__())
print(g.__next__())

g.close()

print(g.__next__())

执行结果:
在这里插入图片描述

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值