Python:浅谈迭代器、生成器与协程的演化路径

“人生苦短,我用Python”,虽然说大量数学和统计分析库是一个重要优势,但是归根结底,Python的最大优势就是三点:

但是通常一般来讲,当扯到并发的时候,无论是多服务器、多进程、多线程、还是协程,事情都难以避免的开始变得复杂。我们把目光放到并发的最轻量级实现:协程上面,简单浅谈一下关于迭代器。

从迭代器说起

迭代器是访问集合元素的一种方式,无需知道集合的内部结构。任何实现了__iter____next__方法的对象都是迭代器。迭代器使得你可以逐个遍历容器内的元素,直到没有更多元素时抛出StopIteration异常。可以很容易实现一个自定义迭代器,这在自己实现一些需要迭代的数据结构式会有些作用:

class MyIterator:
    def __init__(self, max):
        self.current = 0
        self.max = max

    def __iter__(self):
        return self

    def __next__(self):
        if self.current >= self.max:
            raise StopIteration
        value = self.current
        self.current += 1
        return value


# 使用迭代器
for i in MyIterator(5):
    print(i)

输出:

0
1
2
3
4

迭代的艺术:生成器

生成器(Generators)是Python中一种特殊的迭代器。与传统的通过列表、元组等数据结构存储所有元素不同,生成器仅在需要时生成下一个值,大大节省了内存空间。生成器自动实现了迭代器协议,使得编写迭代器更为简单且内存效率更高。

如果想要自行通过迭代器实现与生成器相同功能,也并不困难,如下例子中调用__next__方法与生成器作用类似:

class FibonacciIterator:
    def __init__(self, max_count):
        self.max_count = max_count
        self.current_count = 0
        self.prev = 0
        self.curr = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.current_count >= self.max_count:
            raise StopIteration
        else:
            self.current_count += 1
            if self.current_count == 1:
                return self.prev
            elif self.current_count == 2:
                return self.curr
            else:
                self.prev, self.curr = self.curr, self.prev + self.curr
                return self.curr

# 使用自定义迭代器
fib_iter = FibonacciIterator(10)
print(fib_iter.__next__())
print(fib_iter.__next__())
print(fib_iter.__next__())
print(fib_iter.__next__())
print(fib_iter.__next__())
print(fib_iter.__next__())
print(fib_iter.__next__())

输出:

0
1
1
2
3
5
8

生成器最简单的形式是使用函数定义中的yield语句。每当遇到yield,函数就会暂停并返回一个值给调用者;当再次调用生成器的next()方法时,它会从上次停止的地方继续执行。上面的迭代器程序略显复杂,但是使用生成器之后,程序则变得简单清晰的多。下面的例子使用生成器实现了一样的功能,这可以很好的帮助理解迭代器的运行顺序:


def fibonacci_generator(max_count):
    prev, curr = 0, 1
    count = 0
    while count < max_count:
        yield prev
        prev, curr = curr, prev + curr
        count += 1

# 使用生成器
for num in fibonacci_generator(10):
    print(num)

输出:

0
1
1
2
3
5
8
13
21
34

Python的协程

在Python中,协程(Coroutines)通常被认为是生成器(Generators)的一个超集。它利用生成器的暂停与恢复机制,实现了非阻塞式的并发执行。协程在生成器的基础上进行了扩展,增加了更多的控制流特性,如能够接收输入、暂停执行等。协程是通过生成器实现的,生成器中的yield关键字可以用来实现协程的暂停和恢复执行的功能。Python协程实现,会使用asyncio包,并配合async/await语法糖。

可能只是我个人的YY,似乎Python的协程或多或少的借鉴了JS。从语法到实现方式都非常类似。在现代ES中,async/await语法糖是必不可少,几乎每个程序都会用到的,而Python也是用相同的关键字,从标准化角度,JS先于Python标准化了这两个语法糖。

一个简单的Python使用asyncio的例子如下所示:

import asyncio


async def task(name, delay):
    print(f"{name} start")
    await asyncio.sleep(delay)
    print(f"{name} end")


async def main():
    task1 = asyncio.create_task(task("TAsk1", 2))
    task2 = asyncio.create_task(task("TaSK2", 1))

    await task1
    await task2


asyncio.run(main()

输出:

TAsk1 start
TaSK2 start
TaSK2 end
TAsk1 end

上面代码中,通过asyncio.create_task创建了两个小任务,任务是异步运行的,并且程序必须等待两个任务都结束后,main才会返回。注意这里asyncio.create_task创建的task有些类似于JS的:

new Promise().then()

所以两个task是异步的。如果希望等待Task1完成后再运行Task2,则不需要通过asyncio.create_task创建task,直接再async函数调用前加入await即可,这是JS中一个常用的写法。如下:

import asyncio

async def main():
    await task("TAsk1", 2)
    await task("TaSK2", 1)

asyncio.run(main())

输出:

TAsk1 start
TAsk1 end
TaSK2 start
TaSK2 end

总结

从迭代器,到生成器,最后到协程,理解这个演化路径,可以更好地理解Python的协程机制。在此之后,加上对asyncio库的了解,即可熟练掌握Pythong的协程机制了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/743405.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SHELL/作业/2024/6/25

终端输入两个数&#xff0c;判断两数是否相等&#xff0c;如果不相等&#xff0c;判断大小关系 #!/bin/basha$1b$2 if [ $a -eq $b ]then echo "ab"elif [ $a -gt $b ]thenecho "a>b"elseecho "a<b"fi2.已知网址www.hqyj.com…

Zookeeper 三、Zookeeper基本使用

1.Zookeeper系统模型 1&#xff09;Zookeeper数据模型之ZNode 在Zookeeper中&#xff0c;数据信息被保存在一个个数据节点上&#xff0c;这些节点被称为ZNode。ZNode是Zookeeper中最小数据单位&#xff0c;在ZNode下面又可以再挂ZNode&#xff0c;这样一层层下去就形成了一个…

JVM专题十:JVM中的垃圾回收机制

在JVM专题九&#xff1a;JVM分代知识点梳理中&#xff0c;我们主要介绍了JVM为什么采用分代算法&#xff0c;以及相关的概念&#xff0c;本篇我们将详细拆分各个算法。 垃圾回收的概念 垃圾回收&#xff08;Garbage Collection&#xff0c;GC&#xff09;确实是计算机编程中的…

详解如何在分数限制下,选好专业还是选好学校?

系列文章目录 1、选好专业还是选好学校&#xff1f; 2、具体分段考虑 3、博主给学子的建议 文章目录 系列文章目录前言一、稳定军心二、鱼与熊掌真不可兼得吗&#xff1f;1.兴趣和职业规划2.专业实力3.就业前景4.个人发展 三、具体分段考虑1、高分段考生2、次高分段考生3、中…

住宅IP代理服务终极指南:增强安全性和可访问性

在当今的数字安装程序中&#xff0c;隐私和可访问性对于企业和个人都至关重要。满足这些需求的一个强大工具是住宅 IP 代理服务。这些服务为用户提供住宅 IP 地址&#xff0c;这些地址是互联网产品 (ISP) 计算房主的真实 IP。在本综合指南中&#xff0c;我们将探讨住宅 IP 代理…

手机照片压缩到20k以内免费,这几款心动软件快收好!

在数字化时代&#xff0c;手机拍照已成为我们记录生活的重要方式之一。然而&#xff0c;高清的照片也意味着占用着越来越多的手机存储空间。如果你正在为手机内存告急而烦恼&#xff0c;那么这几款手机照片压缩神器或许能成为你的救星&#xff01;它们不仅可以将照片轻松压缩至…

docker-compose部署Flink及Dinky

docker-compose部署Flink及Dinky 服务器环境&#xff1a;centos7 1. 配置hosts vim /etc/hostsx.x.x.x jobmanager x.x.x.x taskmanager x.x.x.x dinky-mysql2. 文件目录结构 . ├── conf │ ├── JobManager │ │ ├── flink-conf.yaml │ │ ├── log…

高考英语3500词

DAY1 DAY2 DAY3 DAY4 DAY5 DAY6 DAY7 DAY8 DAY9 DAY10 DAY11 DAY12 DAY13 DAY14 DAY15 DAY16 DAY17 DAY18 DAY19 DAY20 DAY21 DAY22 DAY23 DAY24 DAY25 DAY26 DAY27 DAY28 DAY29 DAY30 DAY31 DAY32 DAY33 DAY34 DAY35 DAY36 DAY37 DAY38 DAY39 DAY40

这份AI绘画攻略赶紧码住!超适合小白入门的PS AI插件来啦!

有没有小伙伴对AI绘画很感兴趣&#xff0c;但是看到国外的mj和sd总觉得入门困难&#xff01;别担心&#xff0c;米兔挖到一款超级绝的国产PS AI插件&#xff01;适合新手学习&#xff0c;米兔这里还有一份专为小白准备的AI绘画攻略&#xff0c;让你的创意不再受限&#xff01; …

解决vs2022scanf报错问题

vs2022scanf报错问题 大家下完vs2022之后,开心的写下一段简单的代码: #include <stdio.h> #include <stdlib.h>int main() {int a;scanf("%d", &a);printf("%d", a);return 0; } vs2022会毫不犹豫的报错,下面是报错信息: 翻译过来就是v…

打造智慧矿山:整体架构设计与实践探索

随着信息技术的不断发展&#xff0c;智慧矿山作为矿业领域的创新模式&#xff0c;正日益受到关注。在智慧矿山中&#xff0c;先进的传感器、大数据分析、人工智能等技术被广泛应用&#xff0c;以提高矿山生产效率、降低成本&#xff0c;并确保安全环保。本文将深入探讨智慧矿山…

云计算【第一阶段(20)】磁盘管理与文件系统 服务器硬件及RAID配置实战(三)

一、服务器硬件详解 cpu 主板 内存 硬盘 网卡 电源 raid卡 风扇 远程管理卡 1.1、硬盘尺寸 目前生产环境中主流的两种类型硬盘 3.5寸 和2.5寸硬盘 2.5寸硬盘可以通过使用硬盘托架后适用于3.5寸硬盘的服务器 但是3.5寸没法转换成2.5寸 二、RAID阵列详解 独立硬盘冗余阵…

七天速通javaSE:第三天 程序控制结构:顺序、选择、循环

文章目录 前言一、Scanner类1. hasNext()和hasNextLine()2.next()和nextLine()3. Scanner的其他用法 二、顺序结构三、选择结构1. if单选择结构2. if-else双选择结构3. if-else if多选择结构4. switch选择结构 四、循环结构1. while循环2.do while循环3. for循环&#xff08;常…

Linux系统学习——指令四

Linux系统学习——指令四 Linux 系统学习——指令四查看文件MD5校验和fuser 指令基本语法常用选项访问类型使用示例 系统信息 Linux 系统学习——指令四 查看文件MD5校验和 在Linux中&#xff0c;你可以使用 md5sum 命令来查看一个文件的MD5校验和。以下是具体的操作方法&…

超细毛搭配超宽设计,一款更呵护牙龈的牙刷

牙龈敏感的时候&#xff0c;刷牙特别难受&#xff0c;最近试了试惠百施&#xff08;EBISU&#xff09;65孔宽头软毛牙刷&#xff0c;感觉它的口腔护理体验很不错。这款牙刷的设计独特&#xff0c;采用宽头设计&#xff0c;一次就能刷两排牙齿&#xff0c;极大地提高了清洁效率。…

ServBay[中文] 下一代Web开发环境

ServBay是一个集成式、图形化的本地化Web开发环境。开发者通过ServBay几分钟就能部署一个本地化的开发环境。解决了Web开发者&#xff08;比如PHP、Nodejs&#xff09;、测试工程师、小型团队安装和维护开发测试环境的问题&#xff0c;同时可以快速的进行环境的升级以及维护。S…

解决msvcp120.dll问题的详细步骤,分析msvcp120.dll文件

msvcp120.dll文件是Microsoft Visual C Redistributable Package for Visual Studio 2013中的一个组件。如果提示你丢失该文件&#xff0c;通常意味着程序试图调用一个未在你电脑上安装的Visual C版本。下面是解决此问题的详细步骤。 msvcp120.dll丢失的解决方法 方法 1&#…

报餐小程序可以运用在饭堂的哪方面

随着科技的快速发展&#xff0c;智能化、信息化的管理方式逐渐渗透到我们日常生活的方方面面。在饭堂管理中&#xff0c;报餐小程序的应用为传统的餐饮管理方式带来了革命性的变革。本文将探讨报餐小程序在饭堂管理中的应用及其带来的优势。 一、报餐小程序的基本功能 报餐小程…