目录
  • 什么是迭代
  • 什么是迭代器(Iterator)
  • 可迭代对象
  • for循环的本质
  • 自定义一个列表
  • 实现一个斐波那契数列
  • 什么是生成器(generator)
  • 创建生成器的两种方式
    • 使用推导式创建
    • 使用函数创建
  • 使用generator实现斐波那契数列
    • 什么是协程
      • 协程的基本实现
        • 使用greenlet实现协程
          • 使用gevent实现协程
            • 进程、线程、协程的区别
              • 选择问题
                • 使用协程下载网络的图片
                  • 总结

                    什么是迭代

                    迭代是访问集合元素的一种方式。(迭代和遍历非常相似)

                    什么是迭代器(Iterator)

                    迭代器是一种对象,可以记住遍历的位置的对象。迭代器对象从集的第一个元素开始访问,直到所有的元素被访问完结束。

                    在迭代一个可迭代对象的时候,实际上就是先获取该对象提供的一个迭代器,然后通过这个迭代器来依次获取对象中的每一个数据。

                    可迭代对象

                    某种数据可以通过for….in….的循环语法从其中依次拿到数据进行使用的数据类型,这种数据类型被称为可迭代对象

                    检测某个对象是否是可迭代对象的方法isinstance(待检测对象,Iterable)

                    该方法检测待检测对象是不是Iterable迭代类的子类

                    如果是返回True,如果不是返回False

                    from collections.abc import Iterable
                     
                    """
                    isinstance(待检测对象,Iterable(迭代类,固定写法))
                    判断待检测对象是不是迭代类的一个子类
                    返回值:True可以迭代
                        False不可以迭代
                    """
                    string="fhsudfoh"
                    result=isinstance([1,2,3],Iterable)
                    print(result)

                    for循环的本质

                    for循环的本质是在对一个迭代器进行操作。

                    首先,for循环在遍历可迭代对象的时候会把可迭代对象通过函数iter()或__iter__方法返回一个迭代器,然后在对这个迭代器对象进行操作。

                    迭代器可以用next()或__next__方法得到返回值,当把所有的值取完时会抛出StopIteration错误,这个错误在for循环中python会自己处理,不会展示给开发者。

                    自定义一个列表

                    class MyList(object):
                    # 重写初始化方法,初始化一个数组用来存储数据
                        def __init__(self):
                            self.list = []
                     
                        def __iter__(self):
                    # iter方法返回一个myIterator迭代器对象
                            self.myiterator = MyIterator(self.list)
                            return self.myiterator
                     
                        def additer(self, values):
                    # additer方法用于添加数据
                            self.list.append(values)
                     
                     
                    class MyIterator(object):
                    # 初始化一个下标和接收一个外部的数组变量
                        def __init__(self, my_list):
                            self.list = my_list
                            self.index = 0
                     
                        def __iter__(self):
                            pass
                    # 当对象被迭代器返回后会自动寻找next方法,进行迭代
                        def __next__(self):
                            if self.index < len(self.list):
                                data = self.list[self.index]
                                self.index += 1
                                return data
                            else:
                                raise StopIteration
                     
                     
                    if __name__ == "__main__":
                        mylist = MyList()
                        mylist.additer("张三")
                        mylist.additer("李四")
                        mylist.additer("王五")
                        for value in mylist:
                            print(value)

                    实现一个斐波那契数列

                    class feibonaqi(object):
                        def __init__(self, num):
                            self.fei_list = []
                            self.num = num
                            self.a = 1
                            self.b = 1
                            self.fei_index = 0
                     
                        def __iter__(self):
                            return self
                     
                        def __next__(self):
                            if self.fei_index < self.num:
                                data = self.a
                                self.a, self.b = self.b, self.a + self.b
                                self.fei_index += 1
                                return data
                            else:
                                raise StopIteration
                     
                     
                    if __name__ == '__main__':
                        fei = feibonaqi(5)
                        for i in fei:
                            print(i)

                    什么是生成器(generator)

                    生成器是一个特殊的迭代器,使用了 yield 的函数被称为生成器(generator)。

                    yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。当在生成器函数中使用 yield 语句时,函数的执行将会暂停,并将 yield 后面的表达式作为当前迭代的值返回。然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。可以逐步产生值,而不需要一次性计算并返回所有结果。

                    调用一个生成器函数,返回的是一个迭代器对象。

                    生成器对象可以使用send()方法进行传参。

                    生成器中也可以使用return,当语句执行到return语句之后,生成器会终止迭代,抛出停止迭代的异常。

                    创建生成器的两种方式

                    使用推导式创建

                    result_list = (x * 2 for x in range(10))
                    print(result_list)
                    # 使用生成器生成一个偶数数列[0,2,4,6,8,10,12,14,16,18]
                    # 这边使用next先取出第一个值,后面for循环遍历出来的结果是从0后面开始的
                    value = next(result_list)
                    print(value)
                     
                    for i in result_list:
                        print(i, end=" ")

                    使用函数创建

                    def mygenerator():
                        num_list = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
                        num_index = 0
                        while True:
                            if num_index < len(num_list):
                                yield num_list[num_index]
                            num_index += 1
                     
                     
                    if __name__ == '__main__':
                        mg = mygenerator()
                        value = next(mg)
                        print(value)
                     
                        value = next(mg)
                        print(value)
                     
                        value = next(mg)
                        print(value)

                    使用generator实现斐波那契数列

                    def feibonaqi(num):
                        a = 1
                        b = 1
                        count_index = 0
                        while count_index < num:
                            data = a
                            a, b = b, a + b
                            count_index += 1
                            yield data
                     
                     
                    if __name__ == '__main__':
                        fei = feibonaqi(5)
                        # data=next(fei)
                        # print(data)
                        # data=next(fei)
                        # print(data)
                        # data=next(fei)
                        # print(data)
                        # data=next(fei)
                        # print(data)
                        # data=next(fei)
                        # print(data)
                        for value in fei:
                            print(value)

                    什么是协程

                    协程(coroutine)又称为微线程,是一种用户态的轻量级线程。

                    使用yield可以实现协程,yield可以终止任务执行,并记录任务执行的进度。

                    协程可以实现一个线程执行多个任务

                    协程的基本实现

                    import time
                     
                     
                    def work1():
                        while True:
                            print("正在执行work1。。。。。。。。")
                            yield
                            time.sleep(0.5)
                     
                     
                    def work2():
                        while True:
                            print("正在执行work2.....。。。。。。。。")
                            yield
                     
                     
                    if __name__ == '__main__':
                        w1 = work1()
                        w2 = work2()
                        while True:
                            next(w1)
                            next(w2)

                    使用greenlet实现协程

                    """greenlet是一个第三方库可以提供自行调度的微线程,只需要告诉switch如何运行即可
                        1、导入模块
                        2、创建greenlet对象
                        3、使用switch实现线程的调度
                    """
                     
                    import time
                    from greenlet import  greenlet
                     
                    def work1():
                        while True:
                            print("正在执行work1。。。。。。。。")
                            time.sleep(0.5)
                            g2.switch()
                     
                     
                    def work2():
                        while True:
                            print("正在执行work2...............")
                            time.sleep(0.5)
                            g1.switch()
                     
                     
                    if __name__ == '__main__':
                        g1 = greenlet(work1)
                        g2 = greenlet(work2)
                        g1.switch()

                    使用gevent实现协程

                    import time
                    import gevent
                    from gevent import monkey
                     
                    monkey.patch_all()
                    """gevent也是一个第三方库,自动调度协程,自动识别程序中的耗时操作
                        使用步骤:
                        1、导入模块
                        2、指派任务
                        g1=gevent.spawn(work1)
                        g2=gevent.spawn(work2)
                        3、join()让主线程等待协程进行结束后在退出
                        注意:gevent默认不识别time.slepp(),识别的是gevent.sleep()
                        可以使用打补丁的方式解决,猴子模块
                        from gevent import monkey
                        破解所有monkey.patch_all()
                    """
                     
                     
                    def work1():
                        while True:
                            print("正在执行work1。。。。。。。。")
                            time.sleep(0.5)
                            # gevent.sleep(0.5)
                     
                     
                    def work2():
                        while True:
                            print("正在执行work2...........")
                            time.sleep(0.5)
                            # gevent.sleep(0.5)
                     
                     
                    if __name__ == '__main__':
                        g1 = gevent.spawn(work1)
                        g2 = gevent.spawn(work2)
                        g1.join()
                        g2.join()

                    进程、线程、协程的区别

                    进程是资源分配的基本单位、线程是CPU调度的基本单位、协程是单线程中执行多任务的方式

                    • 切换效率:协程>线程>进程
                    • 高效率方式:进程+协程

                    选择问题

                    • 多进程:密集CPU任务,需要充分使用多核CPU资源(服务器,大量的并行计算)的时候,用多进程
                    • 缺陷:多个进程间通信成本高,切换开销大
                    • 多线程:密集I/O任务(网络I/O、磁盘I/O、数据库I/O)使用多线程合适
                    • 缺陷:同一个时间切片只能运行一个线程,不能做到高并行,但是可以做到高并发
                    • 协程:当程序中存在大量不需要CPU的操作时(I/O),适用协程
                    • 缺陷:单线程执行,处理密集CPU和本地磁盘IO的时候,性能较低。处理网络I/O性能还是比较高的

                    使用协程下载网络的图片

                    """
                    使用协程的方式将网路上的图片下载到本地
                    核心方法:urllib.request.urlopen()打开网址并返回对应的内容(二进制流)
                    """
                    import urllib.request
                    import gevent
                    from gevent import monkey
                     
                    monkey.patch_all()
                     
                     
                    def down_image(url_image, file_name):
                        # 异常处理
                        try:
                            # 打开网络文件
                            request_data = urllib.request.urlopen(url_image)
                            # 打开本地文件
                            with open(file_name, "wb") as file:
                                # 循环读取写入文件
                                while True:
                                    # 从网络中读取1024个字节的数据
                                    file_data = request_data.read(1024)
                                    # 判断数据是否为空,不为空就写入,为空就跳出循环
                                    if file_data:
                                        file.write(file_data)
                                    else:
                                        break
                        except Exception:
                            print("文件%s下载失败" % file_name)
                        else:
                            print("文件%s下载完成" % file_name)
                     
                     
                    def main():
                        img_url1 = "https://img1.baidu.com/it/u=1849885514,1853800516&fm=253&fmt=auto&app=138&f=JPG?w=500&h=500"
                        img_url2 = "https://img2.baidu.com/it/u=4137380440,3737943568&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800"
                        img_url3 = ("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F4e3acf5c-a0fc-44a2"
                                    "-99ff-94f69cae80b4%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com"
                                    "&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1709038944&t=f8e32fd271bb9215553250f0deb5e23d")
                        # joinall()将传入的线程,等待运行完成在结束进程
                        gevent.joinall([
                            gevent.spawn(down_image, img_url1, "img1"),
                            gevent.spawn(down_image, img_url2, "img2"),
                            gevent.spawn(down_image, img_url3, "img3")
                        ])
                     
                     
                    if __name__ == '__main__':
                        main()

                    总结

                    以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

                    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。