【Python】 迭代器、生成器、协程

本文深入解析迭代器和生成器的概念与应用,对比进程、线程与协程的区别,详细阐述如何在Python中使用迭代器和生成器优化内存使用,提升程序效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

迭代器减少了内存空间的同时可以实现循环,

生成器可以让一个函数暂停执行,什么时候又想开始执行的时候继续恢复到上一次的状态开始执行,第一次可以通过next()函数启动,第二次及其以上可以通过send()启动

进程、线程、协程对比

请仔细理解如下的通俗描述

有一个老板想要开个工厂进行生产某件商品(例如剪子)
他需要花一些财力物力制作一条生产线,这个生产线上有很多的器件以及材料这些所有的 为了能够生产剪子而准备的资源称之为:进程
只有生产线是不能够进行生产的,所以老板的找个工人来进行生产,这个工人能够利用这些材料最终一步步的将剪子做出来,这个来做事情的工人称之为:线程
这个老板为了提高生产率,想到3种办法:
在这条生产线上多招些工人,一起来做剪子,这样效率是成倍増长,即单进程 多线程方式
老板发现这条生产线上的工人不是越多越好,因为一条生产线的资源以及材料毕竟有限,所以老板又花了些财力物力购置了另外一条生产线,然后再招些工人这样效率又再一步提高了,即多进程 多线程方式
老板发现,现在已经有了很多条生产线,并且每条生产线上已经有很多工人了(即程序是多进程的,每个进程中又有多个线程),为了再次提高效率,老板想了个损招,规定:如果某个员工在上班时临时没事或者再等待某些条件(比如等待另一个工人生产完谋道工序 之后他才能再次工作) ,那么这个员工就利用这个时间去做其它的事情,那么也就是说:如果一个线程等待某些条件,可以充分利用这个时间去做其它事情,其实这就是:协程方式

简单总结

进程是资源分配的单位
线程是操作系统调度的单位
进程切换需要的资源很最大,效率很低
线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
协程切换任务资源很小,效率高
多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发

具体可以参照代码:
迭代器.py

#__author:bo
#date:2019/4/11

import  time
from collections import Iterable
from collections import Iterator

class Classmate(object):

    def __init__(self):
        self.name=list()  # 定义一个 name 属性,存放 name

    def add(self,name):
        self.name.append(name)

    def __iter__(self):  # 如果要是一个可迭代对象,必须实现 ——iter__ 这个方法
        #  __iter__ 防范必须返回一个对象的引用,这个对象的 next 返回的是什么,则 for 循环中取到的就是什么
        return ClassIterator(self)  # 如果要称为一个迭代器,必须在 __iter__ 方法中返回一个迭代器对象


class ClassIterator(object):
    '''如果要是一个迭代器对象,必须要有 __iter__ __next__ 这两个方法'''
    def __init__(self,obj):
        self.obj=obj
        self.num=0

    def __iter__(self):
        pass

    def __next__(self):
        if self.num<len(self.obj.name): # 防止下标越界
            res=self.obj.name[self.num]
            self.num+=1
            return res
        else:
            raise StopIteration #  如果发生异常,则直接停止迭代,即停止for循环的部分



classmate=Classmate()
classmate.add("111")
classmate.add("222")
classmate.add("333")


for temp in classmate:
    print(temp)
    time.sleep(1)

迭代器升级.py

#__author:bo
#date:2019/4/11

import  time
from collections import Iterable
from collections import Iterator

class Classmate(object):

    def __init__(self):
        self.name=list()  # 定义一个 name 属性,存放 name
        self.num=0

    def add(self,name):
        self.name.append(name)




    def __iter__(self):  # 如果要是一个可迭代对象,必须实现 ——iter__ 这个方法
        #  __iter__ 防范必须返回一个对象的引用,这个对象的 next 返回的是什么,则 for 循环中取到的就是什么
        return self  # 如果要称为一个迭代器,必须在 __iter__ 方法中返回一个迭代器对象

    def __next__(self):
        if self.num < len(self.name):  # 防止下标越界
            res = self.name[self.num]
            self.num += 1
            return res
        else:
            raise StopIteration  # 如果发生异常,则直接停止迭代,即停止for循环的部分



#  将一个类改造成为一个迭代器

#  总结 :迭代器一定是可迭代对象,但是可迭代对象不一定是迭代器,

classmate=Classmate()
classmate.add("111")
classmate.add("222")
classmate.add("333")


for temp in classmate:
    print(temp)
    time.sleep(1)

斐波那契.py

#__author:bo
#date:2019/4/11

import  time
from collections import Iterable
from collections import Iterator

class Fibonacci(object):

    def __init__(self,all_nums):
        self.name=list()  # 定义一个 name 属性,存放 name
        self.current_num=0
        self.all_num=all_nums
        self.a=0
        self.b=1

    def add(self,name):
        self.name.append(name)




    def __iter__(self):  # 如果要是一个可迭代对象,必须实现 ——iter__ 这个方法
        #  __iter__ 防范必须返回一个对象的引用,这个对象的 next 返回的是什么,则 for 循环中取到的就是什么
        return self  # 如果要称为一个迭代器,必须在 __iter__ 方法中返回一个迭代器对象

    def __next__(self):
        if self.current_num<self.all_num:
            res = self.a
            self.a,self.b=self.b,self.a+self.b
            self.current_num+=1
            return res
        else:
            raise StopIteration  # 如果发生异常,则直接停止迭代,即停止for循环的部分



fibo=Fibonacci(10)

for num in fibo:
    print(num)

生成器.py

# __author:bo
# date:2019/4/11

# 只要添加了 yield 就成了生成器,生成器一定是迭代器

def create_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        # print(a)
        yield a  # 如果一个函数中有 yield ,则这个函数不是函数,而是一个生成器模板
        a, b = b, a + b
        current_num += 1


obj1 = create_num(10)  # 创建一个生成器对象,而不是调用函数

res1=next(obj1)
print("obj1 res1",res1)



obj2 = create_num(10)  # 创建一个生成器对象,而不是调用函数

res3=next(obj2)
print("obj2 res3",res3)

res4=next(obj2)
print("obj2 res4",res4)

res2=next(obj1)
print("obj1 res2",res2)  # 创建的两个迭代器不重复,

# 当进行for循环开始的时候,才开始执行 create_num ,第一次到 yield 那儿停下,
# 将 yield 后边的值返回给 num ,然后开始 print,当下一次 for 循环的时候,从
#  create_num的yield 的的下一行开始,一直这样循环,直到退出while循环
# for num in obj:
#     print(num)

生成器升级.py

# __author:bo
# date:2019/4/11

# 只要添加了 yield 就成了生成器,生成器一定是迭代器

def create_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        # print(a)
        yield a  # 如果一个函数中有 yield ,则这个函数不是函数,而是一个生成器模板
        a, b = b, a + b
        current_num += 1
    return "已经结束"  # 如果想得到这个返回值,必须用 excepton 中的 value 来取



obj = create_num(20)  # 创建一个生成器对象,而不是调用函数

while True:
    try:
        res=next(obj)  # 生成器可以用 next 来启动
        print(res)
    except StopIteration as res:  # 当发生异常的时候停止迭代
        print(res.value)  # 想要得到生成器的返回值,来取迭代完成之后的返回值
        break





通过send启动生成器.py

# __author:bo
# date:2019/4/11


def create_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        ret=yield a
        print(">>>ret>>>",ret)
        a, b = b, a + b
        current_num += 1
    return "已经结束"


obj=create_num(10)

res=next(obj)
print(res)  # 这种 next 方式不能往里面传递参数
#  如果想要用 send 不要把 send 放在第一位,第一位一定是 next ,因为第一次没有东西接收 send 传递的参数
res2=obj.send(None)  # send 可以往里面传递参数, send 里面传递的值是下一次 yield 的值
print(res2)





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值