• 迭代器 ,生成器(生成器函数/生成器表达式)


    迭代器需要满足三个条件:

    1,有个__iter__() 方法

    2,有个__next__()方法

    3,迭代到最后一个的时候会抛出异常StopIteration

     1 class DemoClass:
     2     pass
     3 
     4 if __name__ == "__main__":
     5     demo = DemoClass()
     6     for _ in demo:  
     7         pass
     8 
     9 '''
    10     报错:
    11     TypeError: 'DemoClass' object is not iterable
    12 '''
     1 class DemoClass:
     2     def __init__(self,n):
     3         self.n = n
     4     def __iter__(self):
     5         return self  #for in 结构会自动调iter() -->__iter__()
     6     def __next__(self): #  next() -->__next__()
     7         self.n +=1      #还有next中一般要有终止next的条件
     8         if self.n >10:
     9             raise StopIteration
    10         return self.n
    11 
    12 if __name__ == "__main__":
    13     demo = DemoClass(1)
    14 
    15     for i in demo:
    16         print(i,end=' ')
    17         
    18     '''
    19         输出:2 3 4 5 6 7 8 9 10 
    20     '''
     1 class DemoClass:
     2     def __init__(self,n):
     3         self.n = n
     4     def __iter__(self):
     5         return self  #for in 结构会自动调iter() -->__iter__()
     6     def __next__(self): #  next() -->__next__()
     7         self.n +=1      #还有next中一般要有终止next的条件
     8         if self.n >10:
     9             raise StopIteration
    10         return self.n
    11 
    12 if __name__ == "__main__":
    13     demo = DemoClass(1)
    14 
    15     # for i in demo:  #还帮我们捕获了异常StopIteration
    16     #     print(i,end=' ')
    17     
    18     for i in range(10):
    19         demo.__next__()
    20     '''
    21     报错:
    22         StopIteration  #这说明上面的for i in demo 还帮我们捕获了异常
    23     '''

    ###################################新更新################################

    一:什么是迭代器协议?

    1,迭代器协议是一种约定:对象的类中必须提供一个next方法,执行它要么返回下一项;要么引起一个StopIteration异常,以终止迭代。

    2,可迭代对象:它的类中实现了迭代器协议(next 和 StopIteration)。

    3,协议只是一种约定,可迭代对象的类中实现了迭代器协议python中的内部工具(for 循环,sum(),min(),max() 函数等)都是实现迭代器协议。

    二:python中强大的for 循环:

    用for 循环可以 遍历字符串,列表,元组,字典,集合,文件对象。但是它们都不是可迭代对象,只不过在for 循环时,调用了它们内部的__iter__() ,将它们变成了可迭代对象。

    然后,for循环调用可迭代对象的__next__() 去取值。而且,同时也会自动捕捉StopIteration异常,以终止迭代。

    for 循环的工作机制是按迭代器的协议来的,和索引一点关系都没有

     1 l = [1,2,3,5,8,6,4]
     2 
     3 print(l[0])
     4 
     5 #for 循环的本质是按迭代器协议来的,和索引一点关系都没有
     6 for i in l:   #l_iter = l.__iter_() ,l_iter.__next__()
     7     print(i,end=' ')
     8 '''
     9 输出: 
    10 1
    11 1 2 3 5 8 6 4 
    12 '''

    不用for 循环,我们也是可以用索引遍历的。(如下)

     1 l = [1,2,3,5,8,6,4]
     2 index = 0
     3 while 1:
     4     if index >= len(l):
     5         break
     6     else:
     7         print(l[index],end=' ')
     8         index +=1
     9 '''
    10 输出: 1 2 3 5 8 6 4 
    11 '''

    那么问题来了,为什么还要有for 循环

    用索引的方式只能遍历序列类型的,例如列表,元组,字符串。可是非序列类型的呢?它们怎么办呢?例如:字典,集合,文件对象。

    所以,for 循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法

    这个方法就是在迭代之前将它们都变成一个迭代器(通过__iter__()方法),这样就都可以通过for 循环来遍历了。

    用while 来模拟for 循环

     1 l = [1,2,3,5,8,6,4]
     2 iter = l.__iter__()
     3 while 1:
     4     try:
     5         print(iter.__next__(),end=' ')
     6     except StopIteration:
     7         break
     8 '''
     9 输出: 1 2 3 5 8 6 4
    10 '''

    #######################################################################

    一: 生成器

     生成器是特殊的迭代器:

    python 中生成器的表现形式

    1,生成器函数:常规函数定义,不过,使用yield 语句返回,而不是return 语句。yield语句一次返回一个结果,在每个结果结果中间,挂起函数的状态,以使下次从离开的地方继续执行!

    2,生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一整个结果列表

     生成器的特点:Python使用生成器对延迟操作提供了支持。所谓延迟操作是指,在需要的时候才产生结果,而不是立即产生结果。这是生成器的主要好处!

     1,生成器函数:

    1 def func():
    2     yield 1
    3 
    4 g = func()  #生成器函数返回一个生成器对象
    5 print(g)
    6 
    7 '''
    8 输出: <generator object func at 0x000001C5699A70A0>
    9 '''

    yield 的作用

    1),做return 

    2),保留函数的运行状态 

    2,生成器表达式:

    首先看一下,列表解析:

    1 ls =["帅哥{}".format(i) for i in range(10) ]
    2 print(ls)
    3 '''
    4 ['帅哥0', '帅哥1', '帅哥2', '帅哥3', '帅哥4', '帅哥5', '帅哥6', '帅哥7', '帅哥8', '帅哥9']
    5 '''

    生成器表达式和它很像,只是将[]  换成了()

    1 ls =("帅哥{}".format(i) for i in range(10) )
    2 print(ls)  #<generator object <genexpr> at 0x000001B51ADA70A0>
    3 print(ls.__next__())  #帅哥0
    4 print(ls.__next__())  #帅哥1
    5 print(ls.__next__())  #帅哥2
    ls = (i for i in range(10000000000000000000))
    print(sum(ls))
    
    ls =[i for i in range(10000000000000000)]
    print(sum(ls))
    #如果使用下面的写法的话,机器可能会卡死,这就是生成器表达式的好处,它不会一次性的都产生放到列表中。而是用一个拿一个!
     1 import time
     2 t1 = time.perf_counter()
     3 ls = (i for i in range(10000000)) #1千万
     4 print(sum(ls))
     5 print(time.perf_counter()-t1)
     6 
     7 t2 =time.perf_counter()
     8 ls =[i for i in range(10000000)]
     9 print(sum(ls))
    10 print(time.perf_counter()-t2)
    11 '''
    12 49999995000000
    13 1.0159475063914611   生成器表达式还更快
    14 49999995000000
    15 1.20093337520352
    16 '''
     1 import time
     2 t1 = time.perf_counter()
     3 ls = (i for i in range(1000000000)) #10亿
     4 print(sum(ls))
     5 print(time.perf_counter()-t1)
     6 
     7 t2 =time.perf_counter()
     8 ls =[i for i in range(1000000000)]  
     9 print(sum(ls))
    10 print(time.perf_counter()-t2)
    11 '''
    12 499999999500000000
    13 101.18816325276735  #cpu 和内存利用率很低!
    14 终止了!  cpu 和 内存利用率将近100%,
    15 '''

    Python中的大部分内置函数也是使用迭代器协议来访问对象。例如上面的sum函数使用迭代器协议访问对象,所以上面可以用sum 直接对一个生成器求和。

    如果用sum() 直接对列表求和的话,列表是一次性全部生成的,如果数值很大内存是受不了的!

    二:生成器的好处

    1,优点一:延迟计算:(列表解析占用很大内存,生成器表达式几乎不占内存)

    2,优点二:提高代码可读性

     但是迭代器只能迭代一次。之后就不能迭代了。

    补:

    yield 的另一个特性

    x= yield 的另一个特性是接收send()传入的值!send() 同.__next__() 一样也能引起函数继续执行!

     1 def func():
     2     print("begin")
     3     msg = yield "a"
     4     print(msg)
     5     msg = yield "b"
     6     print(msg)
     7 
     8 f = func()
     9 print(f)
    10 ret = f.__next__()  #这行代码执行完之后,生成器执行到了yield "a" ,返回"a" 之后卡住
    11 print(ret)
    12 
    13 ret = f.__next__()  #它执行时从上次卡住的地方开始,然后执行到yield "b" 返回“b”之后卡住
    14 print(ret)
    15 #最后一个msg 没打出来,此时生成器卡在 赋值给msg 处
    16 
    17 '''
    18 输出:
    19     <generator object func at 0x000001C9325A70A0>
    20     begin
    21     a
    22     None #因为没有用send()传入,所以是None
    23     b
    24 '''
     1 def func():
     2     print("begin")
     3     msg = yield "a"
     4     print(msg)
     5     msg = yield "b"
     6     print(msg)
     7 
     8 f = func()
     9 print(f)
    10 ret = f.send(None) #send是向  上次停留  的位置赋值,所以第一次只能传None
    11 print(ret)
    12 
    13 ret = f.send("终于给我赋值了")
    14 print(ret)
    15 
    16 # ret = f.send(1)  #再执行它就报StopIteration
    17 
    18 
    19 '''
    20 输出:
    21     <generator object func at 0x00000209477570F8>
    22     begin
    23     a
    24     终于给我赋值了
    25     b
    26 '''

    1
    def consumer(name): 2 print('My name is "{}" ,I begin to eat!'.format(name)) 3 while 1: 4 food = yield 5 print('"{}" had eat "{}" done!'.format(name,food)) 6 7 c1 = consumer("tom") 8 c1.__next__() 9 c1.send("包子1") #给上次停留位置处传值 10 11 ''' 12 输出: 13 My name is "tom" ,I begin to eat! 14 "tom" had eat "包子1" done! 15 '''

    生产者 ,消费者模型

     1 先看:
     2 import time
     3 def consumer(name):
     4     print('My name is "{}" ,I begin to eat!'.format(name))
     5     while 1:
     6         food = yield
     7         print("eat......")
     8         time.sleep(1)  #模拟吃食物的过程
     9         print('"{}" had eat "{}" done!'.format(name,food))
    10 
    11 c1 = consumer("tom")
    12 
    13 c1.__next__()
    14 c1.send("包子1") #给上次停留位置处传值
    15 
    16 
    17 c1.send("包子2")
    18 
    19 c1.send("包子3")
    20 
    21 '''
    22 输出:
    23     My name is "tom" ,I begin to eat!
    24     ==================================  
         eat......
    25 "tom" had eat "包子1" done! 一个while循环
    26 ===================================
         eat......
    27 "tom" had eat "包子2" done! 28 eat...... 29 "tom" had eat "包子3" done! 30 '''

     生产者每隔1s生产一个,生产完之后发给消费者。

     1 import time
     2 def consumer(name):
     3     print('My name is "{}" ,I begin to eat!'.format(name))
     4     while 1:
     5         food = yield
     6         print("eat......")
     7         time.sleep(1)  #模拟吃食物的过程
     8         print('"{}" had eat "{}" done!'.format(name,food))
     9 
    10 
    11 def producer():
    12     c1 = consumer("tom")  #建立生成器
    13 
    14     c1.__next__()  #第一次先找个地方停止
    15 
    16     for i in range(10):
    17         time.sleep(1)
    18         c1.send("包子{}".format(i))
    19 
    20 producer()
    21 
    22 '''
    23 输出:
    24     My name is "tom" ,I begin to eat!
    25     eat......
    26     "tom" had eat "包子0" done!
    27     eat......
    28     "tom" had eat "包子1" done!
    29     eat......
    30     "tom" had eat "包子2" done!
    31     eat......
    32     "tom" had eat "包子3" done!
    33     eat......
    34     "tom" had eat "包子4" done!
    35     eat......
    36     "tom" had eat "包子5" done!
    37     eat......
    38     "tom" had eat "包子6" done!
    39     eat......
    40     "tom" had eat "包子7" done!
    41     eat......
    42     "tom" had eat "包子8" done!
    43     eat......
    44     "tom" had eat "包子9" done!
    45 '''
     1 import time
     2 def consumer(name,flag):
     3     print('My name is "{} flag is {}" ,I begin to eat!'.format(name,flag))
     4     while 1:
     5         food = yield
     6         print("eat......")
     7         if flag ==0: #吃的慢
     8             time.sleep(10)  #模拟吃食物的过程
     9         else:
    10             time.sleep(0.5)  #吃的快
    11         print('"{}" had eat "{}" done!'.format(name,food))
    12 
    13 def producer():
    14     c1 = consumer("tom",0)  #tom吃的慢
    15     c2 = consumer("jack",1) #jack吃的快
    16 
    17     c1.__next__()  #第一次先找个地方停止
    18     print("====")
    19     c2.__next__()  #第一次先找个地方停止
    20 
    21     c1.send("包子01")  #这行代码知道遇到下个yield 才执行完。所以会一直卡在这
    22     c2.send("包子01")
    23 
    24 
    25 producer()
    26 
    27 '''
    28 输出:
    29 My name is "tom flag is 0" ,I begin to eat!
    30 ====
    31 My name is "jack flag is 1" ,I begin to eat!
    32 eat......(这个过程进行了10s)
    33 "tom" had eat "包子01" done!
    34 eat......
    35 "jack" had eat "包子01" done!
    36 '''
     1 # class test:
     2 #     def __iter__(self):
     3 #         print("__iter__ is called")
     4 #         self.l = [1,2,3]
     5 #         return iter(self.l)
     6 # t = test()
     7 # for i in t:   #t支持迭代器协议,它可以调__iter__()
     8 #     print(i)
     9 #
    10 # #当for i in t 时,实际是:t.__iter__() ,返回一个迭代器对象
    11 # for i in t.__iter__():
    12 #     print(i)
    13 #
    14 # for i in test.__iter__(t):
    15 #     print(i)
    16 '''
    17 输出:
    18 __iter__ is called
    19 1
    20 2
    21 3
    22 __iter__ is called
    23 1
    24 2
    25 3
    26 __iter__ is called
    27 1
    28 2
    29 3
    30 '''
    31 #=======================================
    32 # l = [1,2,5,3,8]
    33 # for i in l:
    34 #     print(i,end=' ')
    35 # #上述for 循环实际是这样工作的:for循环会自动调用迭代器的next方法
    36 # iter_l = iter(l)
    37 # while True:
    38 #     try:
    39 #         i = iter_l.__next__()
    40 #     except StopIteration:
    41 #         break
    42 #     print(i,end=' ')
    43 '''
    44 输出: 1 2 5 3 8 1 2 5 3 8
    45 '''
    46 #=======================================
    47 # f= open("d:/test.txt",'w')
    48 # f.write("Life is short, i learn python!
    ")
    49 # f.write("I love you!
    ")
    50 # f.close()
    51 f =open("d:/test.txt",'r')
    52 for line in f:#文件对象生成的迭代器会自动调用readline()方法
    53     print(line)
    54 f.seek(0)
    55 '''
    56 输出:
    57 Life is short, i learn python!
    58  I love you!
    59 '''
    60 # # 上述的for 循环的原理是:
    61 # while  True:
    62 #     line = f.readline()
    63 #     if line !="":
    64 #         print(line[:-1])
    65 #     else:
    66 #         break
    67 print(f.readlines())
    68 f.seek(0)
    69 it1 = iter(f)
    70 it2 = f.__iter__()
    71 
    72 # print(f.__next__())
    73 # print(it1.__next__())
    74 # print(it2.__next__()) # f ,it1 和 it2 是同一个对象
    75 #注: for 循环都是帮我们自动捕捉StopIteration 异常的
    76 ###########################################
    77 #如果传递两个参数给iter()
    78 #第一个参数必须是callable ,它会重复调第一个参数
    79 class DemoClass:
    80     def __init__(self,l):
    81         self.l = l
    82         # self.iter = iter(self.l)
    83     def __call__(self, *args, **kwargs):
    84         item = 1
    85         print(item)
    86         return item
    87     def __iter__(self):
    88         print("a")
    89         return iter(self)
    90 demo  = DemoClass([1,2,3,4,5]) #demo 是可调用的
    91 
    92 it1 = iter(demo,3)
    随手写的
  • 相关阅读:
    ajax 笔记
    EM Algorithm
    Support Vector Machine
    Factor Analysis
    Local weighted regression
    一点突发奇想
    纳什均衡
    自驾崇明东滩湿地
    程序员热力学第二定律
    SQL Server Identity 属性的问题
  • 原文地址:https://www.cnblogs.com/zach0812/p/11311740.html
Copyright © 2020-2023  润新知