Python进阶:一文搞懂迭代器生成器协程(附案例)

Posted 黑马程序员官方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python进阶:一文搞懂迭代器生成器协程(附案例)相关的知识,希望对你有一定的参考价值。

文章目录


1. [重、难点]自定义迭代对象、迭代器

1、MyList类
1)初始化方法
2)__iter__() 方法,对外提供迭代器
3)addItem() 方法,用来添加数据

2、自定义迭代器类:MyListIterator

  1. 初始化方法
    2)迭代器方法 __iter__()
  2. 获取下一个元素值的方法 __next__()

目标:
mylist = MyList()
for value in mylist:
​ print(value)

2. 迭代器案例:斐波那契数列

  • 自定义了一个 Fibnacci() 迭代器

    • __iter__()
    • __next__()
  • 核心思想:

    a 保存第一列的值

    b 保存第二列的值

    • a = b

    • b = a + b

    • 取 a 的值,得到斐波那契数列

3. [重点]生成器-基本使用

  • 生成器概念: 特殊的迭代器 (按照一定的规律生成数列)

  • 生成器创建方式:

    • 列表推导式

      data_list2 = (x*2 for x in range(10))
      print(data_list2)
      
      # 通过next获取下一个值
      value = next(data_list2)
      print("------->", value)
      
    • 函数中使用了 yield

      # 使用yield 创建了一个生成器
      def test1():
          yield 10
      
      # n 是一个生成器对象
      n = test1()
      print(n)
      
      value = next(n)
      print("----->", value)
      

4. 生成器案例:斐波那契数列

  • 思路:

    1、创建一个生成器
    ​ 目标:实现斐波那契数列
    ​ 1) 定义变量保存第一列和第二列的值
    ​ 2) 定义变量保存当前生成的位置

    3) 循环生成数据,条件(当前的列数 < 总列数)
    4) 保存 a 的值
    5) 修改 a \\ b 的值  (a = b, b = a+b)
    6)  当前列数 + 1
    7)  返回 a 的值 yield
    

    2、定义变量保存生成器
    next(生成器) 得到下一个元素值

  • yield 的作用:

    # 1, 充当return 作用
    # 2, 保存程序的运行状态 并且暂停程序执行
    # 3, 当next 的时候,可以继续唤醒程序从yield位置继续向下执行
    

5. 生成器-使用注意

  • return 的作用

    可以结束 生成器 的运行

  • send的作用,能唤醒生成器,也能传递参数

    next(fib) 可以唤醒 生成器,但是不能传递参数

    生成器.send(传递给生成器的值)

    fib.send(1)

    xxx = yield data # xxx = 1

6. 协程-yield

  • 协程:在不开辟新的线程的基础上,实现多个任务

    协程是一个特殊的生成器

  • 手动实现了协程

    1. work1生成器

    2. work2 生成器

    3. 获取生成器 w1 = work1() w2 = work2()

    4. 协程运行起来

      while True

      ​ next(w1)

      ​ next(w2)

7. 协程-greenlet

  • greenlet 实现协程

    greenlet 是一个第三方的模块,自行的调度的微线程

  • 使用步骤:

    • 导入模块

      from greenlet import greenlet

    • 创建 greenlet 对象

      g1 = greenlet(函数名)

    • 切换任务

      g1. switch()

8. [重点]协程-gevent

  • gevent 也是第三方库,自动调度协程,自动识别程序中的耗时操作

  • 使用步骤:

    • 导入模块

      import gevent

    • 指派任务

      g1 = gevent.spawn(函数名, 参数1,参数2,…)

    • join() 让主线程等待协程执行完毕后再退出

      g1.join

  • gevent 不能识别耗时操作的问题

    • 替换time.sleep() —> gevent.sleep()

    • 打猴子补丁

      1、导入模块 from gevent import monkey

      2、破解所有:monkey.patch_all()

      猴子补丁的作用:

      1. 在运行时替换方法、属性等
      2. 在不修改第三方代码的情况下增加原来不支持的功能
      3. 在运行时为内存中的对象增加patch而不是在磁盘的源代码中增加

9. 进程、线程、协程区别

  • 进程资源分配的基本单位、线程CPU调度的基本单位、协程单线程执行多任务
  • 切换效率: 协程 > 线程 > 进程
  • 高效率方式: 进程 + 协程

选择问题:

多进程:

密集CPU任务,需要充分使用多核CPU资源(服务器,大量的并行计算)的时候,用多进程。

缺陷:多个进程之间通信成本高,切换开销大。

多线程:

密集I/O任务(网络I/O,磁盘I/O,数据库I/O)使用多线程合适。

缺陷:同一个时间切片只能运行一个线程,不能做到高并行,但是可以做到高并发。

协程:

当程序中存在大量不需要CPU的操作时(IO),适用于协程;

10. 案例:并发下载器

  • 案例实现思路:

    1、定义要下载的图片路径
    2、调用文件下载的函数,专门下载文件

    文件下载函数
    1、根据url地址请求网络资源
    2、在本地创建文件,准备保存
    3、读取网络资源数据 (循环)
    4、把读取的网络资源写入到本地文件中
    5、做异常捕获

  • 打开网址 对应的资源

    urllib.request.urlopen(网址)

  • joinall() 批量把协程 添加join

    joinall([协程的列表])

    gevent.joinall([
            gevent.spawn(download_img, img_url1, "1.gif"),
            gevent.spawn(download_img, img_url2, "2.gif"),
            gevent.spawn(download_img, img_url3, "3.gif")
    ])
    

11. 案例:协程版Web服务器

  • 思路:

    1. 导入模块 gevent

    2. 创建协程 gevent.spawn()

      gevent.spawn(self.request_handler, new_client_socket, ip_port)
                  # g1.join()
      
    3. 打补丁

      # 打猴子补丁, 目的:识别程序中的耗时操作
      from gevent import monkey
      monkey.patch_all()
      

以上是关于Python进阶:一文搞懂迭代器生成器协程(附案例)的主要内容,如果未能解决你的问题,请参考以下文章

Python高级语法——协程/迭代器/生成器——学习心得笔记

第十二篇:多任务之协程

python基础-------迭代器,生成器,协程函数

Python函数进阶:闭包装饰器生成器协程

python基础----迭代器生成器协程函数

Python 生成器和协程