• 迭代器 生成器


    • 迭代:迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值
    1 while True:
    2     print('') #只是单纯的重复,因此不是迭代
    3 
    4 lists = [1, 2, 3]
    5 count = 0
    6 while count < len(lists):
    7     print(lists[count])
    8     count += 1
    迭代的概念
    • 为何要有迭代器:对于序列类型的数据(列表,元组,字符串),我们可以使用索引的方法迭代取出每个元素,但对于非序列类型(集合,字典,文件类型等)这类没有的索引的数据,我们就无法使用上述方法,因此就要使用迭代器
    • 迭代器协议:对象必须提供一个next方法,执行该方法的结束是要么返回迭代中的下一项,要么就引起一个Stoplteration异常以终止迭代(只能前进不能后退)
    • 可迭代对象:内置有__iter__方法的对象,即obj.__iter__()
    1 'hello'.__iter__()
    2 [1, 2, 3].__iter__()
    3 ('a', 'b', 1).__iter__()
    4 {'name': 'chen', 'age': 18}.__iter__()
    5 {'a', 1}.__iter__()
    6 open('test').__iter__()
    可迭代对象
    • 迭代器对象:可迭代对象执行obj.__iter__()得到的结果就是迭代器对象,而迭代器对象指的是即内置有__iter__又内置有__next__方法的对
    1 # 文件类型是迭代器对象,因为其内部原始就有__next__()和__iter__()方法
    2 open('a.txt').__iter__()
    3 open('a.txt').__next__()
    迭代器对象
    • 协议:一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for max min sum等函数)使用迭代器协议来访问对象
    • 注:迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象

    for循环机制:

      注:字符串、列表、元组、字典、集合、文件对象,因为其内部有__iter__()方法,故属于可迭代对象,但是本身没有__next__()方法,当用for遍历这些数据类型时,会进行下列操作:

        1.调用这些数据类型中的__iter__()方法,返回值赋值给一个变量,那么这个变量就是迭代器对象

        2.依据迭代器协议,调用__next__()方法,每调用一次就会返回其中的元素,当超出元素个数后,就会报StopIteration错,但是for循环会吞并这个错误,以此来终止循环。

    1 #基于for循环,我们可以完全不再依赖索引去取值了
    2 dic={'a':1,'b':2,'c':3}
    3 for k in dic:
    4     print(dic[k])
    5 
    6 #for循环的工作原理
    7 #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
    8 #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
    9 #3: 重复过程2,直到捕捉到异常StopIteration,结束循环
    for循环机制

    用while循环模拟for循环机制:

    1 l = [1, 2, 3]
    2 iter = l.__iter__()
    3 while True:
    4     try:
    5         print(iter.__next__())
    6     except StopIteration:
    7         print('循环结束了哟!')
    8         break
    View Code
    •  迭代器的优缺点

        优点:----提供一种统一性,不依赖于索引的迭代方法

           ----惰性计算,节省内存

        缺点:----无法获取长度(只有在next完毕后才知道到底有多少个值)

           ----一次性的,只能前进不能后退

    • 生成器:是一种特殊的迭代器,自动实现迭代器协议
    • 生成器优点:1.延迟计算(一次返回一个结果,即不会一次性产生所有结果,对于大量数据来说很有必要)

             2.提高了代码的可读性

    • 创造生成器的方法:

          1.生成器表达式

    1 generator = (i for i in range(5)) #生成器
    2 print(generator) #<generator object <genexpr> at 0x000000C9B4BC0E08>
    3 print(generator.__next__())
    4 print(generator.__next__())
    5 print(generator.__next__())
    6 print(generator.__next__())
    7 print(generator.__next__())
    8 print(generator.__next__()) #StopIteration
    生成器表达式

          2.含有yield的函数:

        1. 语法上与普通函数基本相同,不同点在于用yield代替return来返回值,并且可以有多个yield
        2. 生成器每次调用__next__()方法时,都是从上次迭代结束的位置执行到下个yield的位置,然后将结束的位置作为下次__next__()迭代时的开始位置
     1 def generator():
     2     yield ''
     3     print('开始生儿子啦!')
     4     yield '儿子'
     5     print('开始生孙子啦!')
     6     yield '孙子'
     7 
     8 generator_obj = generator()
     9 # print(generator_obj) #<generator object generator at 0x000000F704810E08>
    10 print('第一次', generator_obj.__next__())  #执行函数内容直到第一个yield后的'我'为止,并停止到这个为止,作为下次next调用的开始
    11 #第一次 我
    12 print('第二次', generator_obj.__next__())  #从print('开始生儿子啦!')执行到第二个yield后的'儿子'为止,作为下次next调用的开始
    13 # 开始生儿子啦!
    14 # 第二次 儿子
    15 print('第三次', generator_obj.__next__()) #从print('开始生孙子啦!')执行到第三个yield后的'孙子'为为止。
    16 # 开始生孙子啦!
    17 # 第三次 孙子
    生成器函数

           生成器函数的优点:可以保留函数的运行状态,运行一次next后就可以进行别的操作,不必等到所有的数据都取出来后才进行操作,相当于“边做边卖”,而不是“都做完了才开始卖”’

    母鸡下蛋的例子比较几种数据产生的方式:

     1 #母鸡下蛋的几种实现方式
     2 
     3 #列表解析的方式
     4 egg_list = ['鸡蛋%s' %i for i in range(1, 5)]
     5 print(egg_list)
     6 #['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']
     7 
     8 #普通函数:全部的蛋都下完了才能进行别的操作
     9 #缺点:1.占用空间大
    10       #2.效率低
    11 def product_egg():
    12     ret = []
    13     for i in range(1, 5):
    14         ret.append('鸡蛋%s' %i)
    15     return ret
    16 egg_list = product_egg()
    17 print(egg_list)
    18 #['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']
    19 
    20 
    21 #生成器函数:边下边进行其他操作
    22 #优点:1.尽可能减少内存的占用
    23         # 2.效率高
    24 def generator_egg():
    25     for i in range(1, 5):
    26         yield '鸡蛋%s' %i
    27 
    28 generator = generator_egg()
    29 print(generator.__next__()) #鸡蛋1
    30 print('休息') #休息
    31 print(generator.__next__()) #鸡蛋2
    母鸡下蛋
  • 相关阅读:
    阿里云服务器mysql连接不了2003 -can't connect to mysql server on 'ip' (10038)
    androidstudio代码混淆
    apk反编译
    android bottomnavicationbar底部图标vector设计
    Java++:不要随意使用 Cookie 会引火烧身的
    Java++:用户认证-基于 jwt 和 session 的区别和优缺点
    Spring++:AOP 拦截 Service | Controller 日志
    Spring++:整合 Retry 实现重试机制
    (xxl_job | quartz):XXL_JOB 对比 Quartz 一决高下!
    Spring++:定时任务 Cron表达式详解
  • 原文地址:https://www.cnblogs.com/SakuraYuanYuan/p/10343077.html
Copyright © 2020-2023  润新知