python协程——1、可迭代、迭代器、生成器

    协程是python中的一个难点,现在开始学习协程,要认识协程首先就要理解生成器。这篇文章主要是巩固生成器的知识。

 

一、理解可迭代、迭代器、生成器

   现在我们常见的额数据类型:str,list,tuple,dict,deque等说起吧,我们借助collections.abc模块与isinstance()来区分来分类吧

from collections.abc import Iterable,Iterator,Generator
import collections

#字符串
str = "123"
print(isinstance(str,Iterable))
print(isinstance(str,Iterator))
print(isinstance(str,Generator))
print("__next__" in dir(str),"\n")

#列表表
list = [1,2,3]
print(isinstance(list,Iterable))
print(isinstance(list,Iterator))
print(isinstance(list,Generator))
print("__next__" in dir(list),"\n")

#元组
tuple = (1,2,3)
print(isinstance(tuple,Iterable))
print(isinstance(tuple,Iterator))
print(isinstance(tuple,Generator))
print("__next__" in dir(tuple),"\n")


#队列
deque = collections.deque([1,2,3])
print(isinstance(deque,Iterable))
print(isinstance(deque,Iterator))
print(isinstance(deque,Generator))
print("__next__" in dir(deque),"\n")



‘’‘

输出结果:

F:\python\python.exe D:/python/python_hight_program/coroutine/yield_from_how.py
True
False
False
False 

True
False
False
False 

True
False
False
False 

True
False
False
False 


Process finished with exit code 0

’‘’

从中可以看出这些对象可迭代,但不是迭代器,接下来我们构建下自己的迭代类和迭代器

1、我们尝试构建自己的可迭代对象

法一、通过__getitem__

#通过__getitem__来写可迭代类
class My_iter:
    def __init__(self,num):
        self.nums = [i for i in range(num)]
    def __getitem__(self, item):
        return self.nums[item]

myiter = My_iter(5)
for i in myiter:
    print(i)

法二、通过__iter__和辅助迭代器

class My_iter2:
    def __init__(self,num):
        self.nums = [i for i in range(num)]
    def __iter__(self):
        return My_iterator(self.nums)

class My_iterator:
    def __init__(self,nums):
        self.nums = nums
        self.index = 0
    def __iter__(self):
        return self
    def __next__(self):
        try:
            sub_nums = self.nums[self.index]
        except IndexError:
            raise StopIteration()
        self.index += 1
        return sub_nums

myiter = My_iter2(5)
for i in myiter:
    print(i)

  iter方法从我们自己创建的迭代器类中获取迭代器(迭代器My_iterator通过__next__来构建),而getitem方法是python内部自动创建迭代器。

2、接下来我们的的重点是生成器,迭代器是在可迭代的基础上加了一个next()方法,而生成器,则是在迭代器的基础上,在实现yield。yield是个什么东西?他相当于我们函数里面的return。在每次next()或者for循环便利的时候都在yield这里将新的返回值返回回去,并在这里阻塞,等待下一次调用。实现节省内存,实现异步编程。

创建生成器的两种方法:

 A、使用推导式

L=(x for x in range(10))

B、实现yield函数

def mygen(n):
    index = 0
    while index < n:
        yeild index
        index += 1

生成器的元素是临时生成的,使用节省空间内存。

最后我们总结一下:

(1)什么是可迭代对象? 可迭代对象要么实现了能返回迭代器的 iter 方法,要么实现了 getitem 方法而且其参数是从零开始的索引。

(2)什么是迭代器? 迭代器是这样的对象:实现了无参数的 next 方法,返回下一个元素,如果没有元素了,那么抛出 StopIteration 异常;并且实现iter 方法,返回迭代器本身。

(3)什么是生成器? 生成器是带有 yield 关键字的函数。调用生成器函数时,会返回一个生成器对象。 

(4)什么是生成器表达式? 生成器表达式是创建生成器的简洁句法,这样无需先定义函数再调用。 

二、使用生成器

1、如何运行、激活生成器

  两种激活方法:

      A.使用next()     

       B.使用generator.send(None)

def gen_func():
    yield 1
    yield 2
    yield 3

gen = gen_func()
print(gen.send(None))
print(next(gen))

输出

1
2

2、生成器的执行状态

生成器在其生命周期中,会有如下四个状态

    GEN_CREATED   #等待开始执行

     GEN_RUNNING   #生成器正在执行(只有多线程应用中才能看到这个状态)

     GEN_SUPENDED  #在yield表达式处暂停

     GEN_CLOSED     #执行结束

from inspect import getgeneratorstate

def mygen(n):
    index = 0
    while index < n:
        yield index
        index += 1

if __name__ == "__main__":
    gen = mygen(2)
    print(getgeneratorstate(gen))

    print(next(gen))
    print(getgeneratorstate(gen))

    print(next(gen))
    gen.close()
    print(getgeneratorstate(gen))

      输出

GEN_CREATED
0
GEN_SUSPENDED
1
GEN_CLOSED
 

3、生成器的异常处理

在生成器工作过程中,若生成器不满足生成元素的条件,就/应该 抛出异常(StopIteration)。

所以我们在自己定义一个生成器的时候,我们也应该在不满足生成元素条件的时候,抛出异常。
拿上面的代码来修改一下。

def mygen(n):
    index = 0
    while index < n:
        yield index
        index += 1
    raise StopIteration

4\从生成器到协程:yield

通过上面的介绍,我们知道生成器为我们引入了暂停函数执行(yield)的功能。当有了暂停的功能之后,人们就想能不能在生成器暂停的时候向其发送一点东西(其实上面也有提及:send(None))。这种向暂停的生成器发送信息的功能通过 PEP 342 进入 Python 2.5 中,并催生了 Python协程的诞生。根据 wikipedia 中的定义

协程是为非抢占式多任务产生子程序的计算机程序组件,协程允许不同入口点在不同位置暂停或开始执行程序。

注意从本质上而言,协程并不属于语言中的概念,而是编程模型上的概念。

协程和线程,有相似点,多个协程之间和线程一样,只会交叉串行执行;也有不同点,线程之间要频繁进行切换,加锁,解锁,从复杂度和效率来看,和协程相比,这确是一个痛点。协程通过使用 yield 暂停生成器,可以将程序的执行流程交给其他的子程序,从而实现不同子程序的之间的交替执行。

下面通过一个简明的演示来看看,如何向生成器中发送消息。

def j_range(n):
    index = 0
    while index<n:
        j = yield index
        if j is None:
            j = 1
        index += j

if __name__ == "__main__":
    iter = j_range(5)
    print(next(iter))
    print(iter.send(3))
    print(next(iter))
    print(iter.send(-2))

 

输出

0
3
4
2

这里解释下为什么这么输出。
重点是jump = yield index这个语句。

分成两部分:

  • yield index 是将index return给外部调用程序。
  • jump = yield 可以接收外部程序通过send()发送的信息,并赋值给jump

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中的迭代器生成器是一种基于惰性计算的概念,它们可以有效地处理大量的数据或者无限序列。下面我将分别介绍迭代器生成器迭代器(Iterator)是一个实现了迭代协议(Iterator Protocol)的对象。通过调用内置函数 `iter()` 可以将可迭代对象转换为迭代器迭代器对象可以使用内置函数 `next()` 来逐个访问数据元素,直到没有更多的元素可供访问时,会引发 `StopIteration` 异常。例如,可以使用迭代器来遍历列表、元组、集合等容器类型的数据。 生成器(Generator)则是一种特殊的迭代器。它不需要显式地实现迭代协议,而是通过函数中的 `yield` 关键字来实现惰性计算。生成器函数在每次调用时返回一个值,并在下一次调用时从上一次离开的位置继续执行。这样可以节省大量的内存空间,并且提高程序的效率。生成器函数定义时使用 `def` 关键字,并包含至少一个 `yield` 关键字。 下面是一个简单的示例代码,演示了如何使用迭代器生成器: ```python # 使用迭代器遍历列表 my_list = [1, 2, 3, 4, 5] my_iter = iter(my_list) while True: try: item = next(my_iter) print(item) except StopIteration: break # 使用生成器生成斐波那契数列 def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b fib = fibonacci() for i in range(10): print(next(fib)) ``` 希望以上解释能够帮助你理解迭代器生成器的概念。如果有任何进一步的问题,请随时提问!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值