Python 生成器

小初seo 学习笔记评论295字数 1122阅读3分44秒阅读模式
摘要Python生成器处理序列时允许序列中的每一个值只在需要时才计算

Python生成器处理序列时允许序列中的每一个值只在需要时才计算,而不是提前计算。

举个例子,当我们要遍历2的32次方的整数时,如果用一个列表来存这么多数字,内存直接就被撑爆了。相反我们如果使用生成器,则可以在需要时再计算列表中的值。

>>> 2**324294967296>>> L = [x for x in range(2**32)]

Python 生成器-图片1

我们将上面的例子转换为一个生成器,看下生成器是如何工作的:

def bigList(n):    i = 0    while i < n:        yield i        i = i + 1
L = bigList(2*32)for i in L:    print(i)

此时得到的 L 并不是一个列表,它实际上是一个生成器。语句运行到 yield 时暂停并将结果返回给调用者。与 return 语句不同的是, yield 语句不会终止函数执行,而是暂时在返回的位置等待下次调用生成器。

生成器也是函数,它使用 yield 语句代替 return。Python 提供了一个内置函数 next 用来请求生成器的下一个值。

>>> L = bigList(2*32)>>> next(L)0>>> next(L)1>>> next(L)2>>> next(L)3

其中 next 是单向的,如果我们想回退怎么办?这里有一个内置方法 send 可以干预 yield 值,相当于给 yield 重新传了一个值。这里需要将生成器改造一下,方便 send 传值。

def bigList(n):    i = 0    while i < n:        ret = yield i        if ret != None:            i = int(ret)        else:            i = i + 1

Python 生成器-图片2

当调用 send 时,值被传回了 yield i  表达式。此时返回值不为 None,通过 if 语句更改生成器逻辑重新生成  i 的值,然后进入下一轮循环再次卡在 yield 语句。

当正常调用 next 时,yield 语句返回 None。当调用 send 时,语句从 yield 语句开始执行,传回来的值进入 yield 返回一个非 None 值,然后接着执行下面的语句。执行完后进入下一轮循环,然后再次调用 yield 语句返回。也就是说 send 语句通过传值更改执行逻辑后再次调用 yield 语句返回了一个值。在 yield 语句中打上输出标记可以看到执行的逻辑。

def bigList(n):    i = 0    while i < n:        ret = yield '!',i        print('# ', ret)        print()        if ret != None:            i = int(ret)        else:            i = i + 1        print('## ', i)
L = bigList(2**32)print(next(L))print('#'*10)print('### ', L.send(111))
print('#'*10)print('### ', L.send(0))

Python 生成器-图片3

全文完。

 
  • 本文由 小初seo 发表于 2022年12月31日17:24:37
  • 转载请务必保留本文链接:https://www.pkak.cn/xuexi/9081.html
匿名

发表评论

匿名网友
:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

拖动滑块以完成验证