• python基础----迭代器、生成器、协程函数及应用(面向过程实例)


    一、什么是迭代器协议

    1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)

    2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)

    3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。

    二,为什么要用迭代器

    优点:

    1:迭代器提供了一种不依赖于索引的取值方式,这样就可以遍历那些没有索引的可迭代对象了(字典,集合,文件)

    2:迭代器与列表比较,迭代器是惰性计算的,更节省内存

    缺点:

    1:无法获取迭代器的长度,使用不如列表索引取值灵活

    2:一次性的,只能往后取值,不能倒着取值

    1 l=['a','b','c','d','e']
    2 i=l.__iter__()
    3 while True:
    4     try:
    5         print(next(i))
    6     except StopIteration:
    7         break
    课堂例1
    1 d={'a':1,'b':2,'c':3}
    2 d.__iter__
    3 for k in d:        #d.__iter__()
    4     print(k)
    课堂例2
     1 s={1,2,3,4}
     2 for i in s:
     3     print(i)
     4 
     5 with open('a.txt','r') as f:
     6     for line in f:
     7         print(line)
     8 
     9 f=open('a.txt','r')
    10 f.__next__
    11 f.__iter__
    12 print(f)
    13 print(f.__iter__())
    14 
    15 for line in f: #f.__iter__()
    16     print(line)
    17 
    18 i=f.__iter__()
    19 
    20 while True:
    21     try:                     #异常排查,与StopIteration一起用
    22         print(next(i))
    23     except StopIteration:     #异常排查,与try一起用      # except 排除
    24         break
    课堂例3
     1 l=[1,2,3]
     2 print(len(l))
     3 i=l.__iter__()
     4 
     5 print(next(i))
     6 print(next(i))
     7 print(next(i))
     8 print(next(i))
     9 
    10 
    11 for x in i:
    12     print(x)
    13 for x in i:
    14     print(x)
    15 for x in i:
    16     print(x)
    17 for x in i:
    18     print(x)
    课堂例4
     1 查看可迭代对象与迭代器对象
     2 
     3 from collections import Iterable,Iterator
     4 
     5 s='hello'
     6 l=[1,2,3]
     7 t=(1,2,3)
     8 d={'a':1}
     9 set1={1,2,3,4}
    10 f=open('a.txt')
    11 
    12 都是可迭代的
    13 s.__iter__()
    14 l.__iter__()
    15 t.__iter__()
    16 d.__iter__()
    17 set1.__iter__()
    18 f.__iter__()
    19 print(isinstance(s,Iterable))
    20 print(isinstance(l,Iterable))
    21 print(isinstance(t,Iterable))
    22 print(isinstance(d,Iterable))
    23 print(isinstance(set1,Iterable))
    24 print(isinstance(f,Iterable))
    25 
    26 查看是否是迭代器
    27 print(isinstance(s,Iterator))
    28 print(isinstance(l,Iterator))
    29 print(isinstance(t,Iterator))
    30 print(isinstance(d,Iterator))
    31 print(isinstance(set1,Iterator))
    32 print(isinstance(f,Iterator))
    课堂例5

    三、生成器

    什么是生成器:

    可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象.

    from collections import Iterator   生成器就是一个函数,这个函数内包含有yield这个关键字  。◕‿◕。

    生成器分类及在python中的表现形式:(Python有两种不同的方式提供生成器)

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

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

    为何使用生成器:

    优点:

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

    生成器小结:

    1.是可迭代对象

    2.实现了延迟计算,省内存

    3.生成器本质和其他的数据类型一样,都是实现了迭代器协议,只不过生成器附加了一个延迟计算省内存的好处,其余的可迭代对象可没有这点好处,记住喽!!!

    生成器与return的区别:return只能返回一次函数就彻底结束了,而yield能返回多次值
                     
    yield功能:

    1.yield把函数变成生成器-->生成器本质就是迭代器,相当于把__iter__和__next__方法封装到函数内部

    2.用return返回值能返回一次,而yield返回多次

    3.函数暂停以及继续运行的状态是通过yield保存的

     插一嘴:

    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

    所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

    1 >>> L = [x * x for x in range(10)]
    2 >>> L
    3 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    4 >>> g = (x * x for x in range(10))
    5 >>> g
    6 <generator object <genexpr> at 0x1022ef630>

    创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。

    我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

    如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

     1 >>> next(g)
     2 0
     3 >>> next(g)
     4 1
     5 >>> next(g)
     6 4
     7 >>> next(g)
     8 9
     9 >>> next(g)
    10 16
    11 >>> next(g)
    12 25
    13 >>> next(g)
    14 36
    15 >>> next(g)
    16 49
    17 >>> next(g)
    18 64
    19 >>> next(g)
    20 81
    21 >>> next(g)
    22 Traceback (most recent call last):
    23   File "<stdin>", line 1, in <module>
    24 StopIteration

    我们讲过,generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

    生成器本质就是迭代器

     1 def func():
     2         n=0
     3         while True:
     4              yield n
     5              n+=1
     6              
     7     g=func()
     8 
     9     res=next(g)
    10     res=next(g)
    11 
    12     for i in g:
    13         pass

    yield的表达式形式:

    1 food=yield
    2     
    3 def eater(name):
    4     print('%s start to eat' %name)
    5     while True:
    6         food=yield
    7         print('%s eat %s' %(name,food))
    8         
    9 e=eater('zhejiangF4')

    e.send与next(e)的区别
              1.如果函数内yield是表达式形式,那么必须先next(e)
              2.二者的共同之处是都可以让函数在上次暂停的位置继续运行,不一样的地方在于send在触发下一次代码的执行时,会顺便给yield传一个值

     1 def test():
     2     print('one')
     3     yield 1 #return 1
     4     print('two')
     5     yield 2 #return 2
     6     print('three')
     7     yield 3 #return 2
     8     print('four')
     9     yield 4 #return 2
    10     print('five')
    11     yield 5 #return 2
    12 
    13 g=test()
    14 print(g)
    15 # print(isinstance(g,Iterator))
    16 g.__iter__()
    17 g.__next__()
    18 
    19 res=next(g)
    20 print(res)
    21 
    22 res=next(g)
    23 print(res)
    24 
    25 res=next(g)
    26 print(res)
    27 
    28 res=next(g)
    29 print(res)
    30 
    31 for i in g:
    32     print(i)
    课堂例1
    1 def func():
    2     n=0
    3     while True:
    4         yield n
    5         n+=1
    6 
    7 f=func()
    8 print(next(f))
    课堂例2
     1 import time
     2 def tail(file_path):
     3     with open(file_path,'r') as f:
     4         f.seek(0,2)
     5         while True:
     6             line=f.readline()
     7             if not line:
     8                 time.sleep(0.3)
     9                 continue
    10             else:
    11                 # print(line)
    12                 yield line
    13 tail('/tmp/a.txt')
    课堂例3
     1 def countdown(n):
     2     print('start coutdown')
     3     while n > 0:
     4         yield n #1
     5         n-=1
     6     print('done')
     7 
     8 g=countdown(5)
     9 print(g)
    10 
    11 print(next(g))
    12 print(next(g))
    13 print(next(g))
    14 print(next(g))
    15 print(next(g))
    16 print(next(g))
    17 
    18 for i in g: #iter(g)
    19     print(i)
    20 
    21 while True:
    22     try:
    23         print(next(g))
    24     except StopIteration:
    25         break
    课堂例4

    四、协程函数 

    定义:如果在一个函数内部yield的使用方式是表达式形式的话,如x=yield,那么该函数成为协程函数  。◕‿◕。

     #例子

    1
    def eater(name): 2 print('%s start to eat food' %name) 3 food_list=[] 4 while True: 5 food=yield food_list 6 print('%s get %s ,to start eat' %(name,food)) 7 food_list.append(food) 9 print('done') 10 e=eater('钢蛋') 11 print(e) 12 print(next(e)) 13 print(e.send('包子')) 14 print(e.send('韭菜馅包子')) 15 print(e.send('大蒜包子'))

    为协程函数添加装饰器:

     1 def timmer(func):
     2     def wrapper(*args,**kwargs):
     3         e=func(*args,**kwargs)
     4         next(e)
     5         return e
     6     return wrapper
     7 
     8 @timmer        #eater=timmer(eater)
     9 def eater(name):
    10     print('%s start to eat food' %name)
    11     food_list=[]
    12     while True:
    13         food=yield food_list
    14         print('%s get %s ,to start eat' %(name,food))
    15         food_list.append(food)
    16 e = eater('egon')   #wrapper('egon')
    17 # print(e)
    18 # next(e)
    19 print(e.send('包子'))
    20 print(e.send('包子'))   #以下每send一次都会执行一次结果
    21 print(e.send('包子'))
    22 print(e.send('包子'))

     补充:

     1 def init(func):
     2     def wrapper(*args,**kwargs):
     3         res=func(*args,**kwargs)
     4         next(res)
     5         return res
     6     return wrapper
     7 
     8 @init #eater=init(eater)
     9 def eater(name):
    10     print('%s start to eat' % name)
    11     food_list=[]
    12     while True:
    13         food = yield food_list
    14         print('%s eat %s' % (name, food))
    15         food_list.append(food)
    16 
    17 e = eater('zhejiangF4') #wrapper('zhengjiangF4')
    18 # print(e)
    19 # next(e) #e.send(None)
    20 
    21 print(e.send('123'))
    22 print(e.send('123'))
    23 print(e.send('123'))
    24 print(e.send('123'))
    25 print(e.send('123'))

    五、协程函数的应用

    面向过程的编程思想:流水线式的编程思想,在设计程序时,需要把整个流程设计出来

    优点:   1:体系结构更加清晰

               2:简化程序的复杂度

    缺点:可扩展性极其的差,所以说面向过程的应用场景是:不需要经常变化的软件,如:linux内核,httpd,git等软件

     旁白: 此实例包含了装饰器、迭代器、生成器、协程函数、os模块中walk命令,需要好好记住! ♥♥♥♥♥。◕‿◕。♥♥♥♥♥

     1 #grep -rl 'python' C:egon
     2 import os,time
     3 def init(func):
     4     def wrapper(*args,**kwargs):
     5         res=func(*args,**kwargs)
     6         next(res)
     7         return res
     8     return wrapper
     9 
    10 #找到一个绝对路径,往下一个阶段发一个
    11 @init
    12 def search(target):
    13     '找到文件的绝对路径'
    14     while True:
    15         dir_name=yield #dir_name='C:\egon'
    16         print('车间search开始生产产品:文件的绝对路径')
    17         time.sleep(2)
    18         g = os.walk(dir_name)
    19         for i in g:
    20             # print(i)
    21             for j in i[-1]:
    22                 file_path = '%s\%s' % (i[0], j)
    23                 target.send(file_path)
    24 
    25 @init
    26 def opener(target):
    27     '打开文件,获取文件句柄'
    28     while True:
    29         file_path=yield
    30         print('车间opener开始生产产品:文件句柄')
    31         time.sleep(2)
    32         with open(file_path) as f:
    33             target.send((file_path,f))
    34 
    35 @init
    36 def cat(target):
    37     '读取文件内容'
    38     while True:
    39         file_path,f=yield
    40         print('车间cat开始生产产品:文件的一行内容')
    41         time.sleep(2)
    42         for line in f:
    43             target.send((file_path,line))
    44 
    45 @init
    46 def grep(pattern,target):
    47     '过滤一行内容中有无python'
    48     while True:
    49         file_path,line=yield
    50         print('车间grep开始生产产品:包含python这一行内容的文件路径')
    51         time.sleep(0.2)
    52         if pattern in line:
    53             target.send(file_path)
    54 
    55 @init
    56 def printer():
    57     '打印文件路径'
    58     while True:
    59         file_path=yield
    60         print('车间printer开始生产产品:得到最终的产品')
    61         time.sleep(2)
    62         print(file_path)
    63 
    64 
    65 g=search(opener(cat(grep('python',printer()))))
    66 g.send('C:\egon')
    67 g.send('D:\dir1')
    68 g.send('E:\dir2')
    面向过程实例
  • 相关阅读:
    余额宝数据架构阅读
    VS提示This function or variable may be unsafe,The POSIX name for this item is deprecated
    VS中新建QT空项目找不到头文件的问题
    指针
    循环for do while continue break,达夫设备
    GUI程序弹出控制台打印输出信息
    ctime、chrono以及所有和时间有关的内容
    python安装
    文件:fstream,FILE,CFile,filesystem,以及路径目录
    C++异常处理、Dump文件、断言、静态断言、日志文件
  • 原文地址:https://www.cnblogs.com/wangyongsong/p/6694496.html
Copyright © 2020-2023  润新知