前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python 迭代器和生成器(5.2)

python 迭代器和生成器(5.2)

作者头像
友儿
发布2022-09-28 13:23:37
1860
发布2022-09-28 13:23:37
举报
文章被收录于专栏:友儿

迭代器和生成器

迭代器

概念上: 迭代器可以用来表示一个数据流, 提供了数据的惰性返回功能(只有我们主动去使用next方法调用, 才会返回值).

实现上: 实现了__next__接口的对象

传统声明一个列表, 里面的元素会立即写进内存当中, 占用大量内存. 迭代器可以一次只返回一个元素, 占用内存非常小, 在读取大文件和大的数据集合的时候特别有用

通过iter方法返回一个迭代器对象

代码语言:javascript
复制
# 两者实现的功能是一摸一样的
l = list(range(10**7))
l2 = iter(range(10**7))

通过next方法主动获取迭代器中的值

代码语言:javascript
复制
# 当迭代器中没有值了以后, 会抛出StopIteration的异常, 需要大家自行处理一下
l = iter(range(5))
print(next(l))
print(next(l))
print(next(l))
print(next(l))
print(next(l))
print(next(l))

生成器

生成器是一种特殊的迭代器, 在迭代器惰性返回数据的基础上, 提供了额外的功能, 实现了程序的暂停.

声明一个生成器

只要函数体中有yield关键词, 它就是一个生成器

yield翻译为让渡, 我们可以简单理解为暂停并返回右边的值

代码语言:javascript
复制
def my_range_gen(n):
    for i in range(n):
        yield i*i
        print(f"current index: {i}")

my_range = my_range_gen(10)
print(my_range)
print(next(my_range))
print(next(my_range))
print(next(my_range))
print(next(my_range))

生成器和迭代器的区别?

同样提供了惰性返回的功能, 迭代器侧重于提供数据的惰性返回功能, 生成器侧重于指令的惰性返回功能

协程

协程的原理

协程的实现原理就是生成器的实现原理, 在生成器的基础上又提供了传递值的功能.

通过send方法向生成器传递值, 以下例子中, b就是通过send方法赋值为2

对生成器进行send操作一定要调用next方法预激, 使其停留在第一个yield位置

代码语言:javascript
复制
def simple_coro(a):
    print("初始值 a=", a)
    b = yield a
    print("传递值 b=", b)
    c = yield a + b
    print("传递值 c=", c)

coro = simple_coro(1)
print(next(coro))
print(coro.send(2))
print(coro.send(3))

用协程实现计算平均数的函数

代码语言:javascript
复制
def coro_avg():
    total = 0
    length = 0
    while True:
        try:
            value = yield total/length
        except ZeroDivisionError:
            value = yield 0
        total += value
        length += 1

my_avg = coro_avg()
print(next(my_avg))
print(my_avg.send(2))
print(my_avg.send(3))

yieldyield from

yield from实现的协程异步程序晦涩难懂, 在python3.4引用asyncio标准库之后被弃用

yield from 用来驱动子程序中的循环并返回最终值

代码语言:javascript
复制
def return_triple():
    while True:
        value = yield
        if value % 3 == 0:
            return value


def triple_recorder():
    while True:
        result = yield from return_triple()
        triple_array.append(result)

triple_array = []
coro = triple_recorder()
next(coro)
for i in range(100):
    coro.send(i)
print(triple_array)

异步I/O

asyncio(异步)

Python3.4引入的标准库, 替换yield from实现协程异步IO, 可以更好地实现异步程序

实现原理: 自动维护了一个事件队列, 然后循环访问事件来完成异步的消息维护.

代码语言:javascript
复制
import asyncio
import time


class Response:
    staus_code = 200


async def sim_request(index):
    print(f"模拟发送请求 Index: {index}")
    response = Response()
    # 模拟网络延迟
    # 当前是单线程运行的, 如果调用的是time.sleep(1), 那么这个线程会被阻塞
    # 当前线程被阻塞之后, 不会让渡cpu资源, 异步的效率就不会体现
    await asyncio.sleep(1)
    print(f"request index {index}, response status_code: {response.staus_code}")
    return response.staus_code

# 获取消息队列
loop = asyncio.get_event_loop()

# 包装任务
task_array = []
for i in range(100):
    task_array.append(sim_request(i))

# 循环访问事件来完成异步的消息维护
loop.run_until_complete(asyncio.wait(task_array))

# 关闭事件循环
loop.close()

当前异步实际上有没有提高效率, 也关乎到你调用的第三方是不是异步的.

这也是当前python异步的一个痛点, 就是丰富的第三方库不是都支持asyncio的.

小技巧: 获取异步完成之后的所有返回值

代码语言:javascript
复制
result = loop.run_until_complete(asyncio.gather(*task_array))
print(result)
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022 年 09 月,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 迭代器和生成器
  • 协程
  • 异步I/O
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档