• c迭代器与生成器


    一:迭代器

    1.什么是迭代?

      1.重复   2.下一次重复是基于上一次的结果

    # l=['a','b','c','d']
    # count=0
    # while count < len(l):
    #     print(l[count])      #count的值基于上一次结果,所以是迭代
    # count+=1

    2.迭代器协议

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

       python 为了提供一种不依赖索引的迭代方式
      以obj=[1,2,3,,4,5]为例:
           python会为一些对象内置.__iter__方法,能够.__iter__的都是可以成为可迭代对象.
             如果我们obj.__iter__()后得到一个结果就是迭代器。  迭代器既有.__iter__ 方法又有 .__next__方法.
     

      迭代器的优点:
        1.提供了一种不依赖索引的迭代方式
        2.惰性计算,节省内存

      迭代器的缺点:
        1.取值不如按照索引取值的方便
        2.只能前进,不能后退
        3.无法获取长度

    判断是否为可迭代对象或者迭代器对象的方法:

    以a=[1,2,3,4]为例:
    方法一:
       obj=a.__iter__()     说明他是可迭代对象,obj成为迭代器
       obj.__next__()       说明obj是迭代器对象
    方法二: 
       from collections import Iterable,Iterator    #调用相应模块,测试是否为可迭代对象或者迭代器对象
        print(isinstance(a,Iterable))   #判断是否为可迭代对象,如果是则返回True
           print(isinstance(a,Iterator))   #判断是否为迭代器对象,如果是则返回True
    # # from collections import  Iterable,Iterator
    # # print(isinstance(g,Iterator)) #可判断是够为迭代器对象
    # def countdown(n):
    #     print('starting countdown')
    #
    #     while n > 0:
    #         yield n
    #         n-=1
    #     print('stop countdown')
    # g=countdown(5)
    
    # print(g.__next__())
    # print(g.__next__())
    # for i in g:
    #     print(i)
    View Code

     3 迭代器

      在介绍迭代器之前,我们先来了解一下容器这个概念。

        容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取。简单来说,就好比一个盒子,我们可以往里面存放数据,也可以从里面一个一个地取出数据。在python中,属于容器类型地有:list,dict,set,str,tuple.....。容器仅仅只是用来存放数据的,我们平常看到的 l = [1,2,3,4]等等,好像我们可以直接从列表这个容器中取出元素,但事实上容器并不提供这种能力,而是可迭代对象赋予了容器这种能力。

       说完了容器,我们在来谈谈迭代器。迭代器与可迭代对象区别在于:__next__()方法。

      我们可以采用以下方法来验证一下:

    from collections import Iterator
    
    f = open('a.txt')
    i = 1
    s = '1234'
    d = {'abc':1}
    t = (1, 2, 344)
    m = {1, 2, 34, }
    
    print(isinstance(i,Iterator))
    print(isinstance(s,Iterator))
    print(isinstance(d,Iterator))
    print(isinstance(t,Iterator))
    print(isinstance(m,Iterator))
    print(isinstance(f,Iterator))
    
    ########输出结果##########
    False
    False
    False
    False
    False
    True
    View Code

      结果显示:除了文件对象为迭代器,其余均不是迭代器

      下面,我们进一步来验证一下:

    print(hasattr(i,"__next__"))
    print(hasattr(s,"__next__"))
    print(hasattr(d,"__next__"))
    print(hasattr(t,"__next__"))
    print(hasattr(m,"__next__"))
    print(hasattr(f,"__next__"))
    
    #######结果###########
    False
    False
    False
    False
    False
    True
    View Code

    从输出结果可以表明,迭代器与可迭代对象仅仅就是__next__()方法的有无

    ——————--模拟linux中的taif -f a.txt |grep 'error'  |grep '404'
     
    '模拟linux中'
    #tail -f a.txt
    import time
    def tail(filepath,encoding='utf-8'):
        with open(filepath,encoding=encoding) as f:
            f.seek(0,2)
            while True:
                line=f.readline()
                if line:
                    print(line,end='')
                    # yield line
                else:
                    time.sleep(0.5)
    
    tail('b.txt')
    
    # for i in g:
    #     print(i)
    
    #tail -f a.txt |grep 'error'
    
    # def grep(lines,pattern):
    #     for line in lines:
    #         if pattern in line:
    #             # print(line,end='')
    #             yield line
    
    # g=tail('a.txt')
    # print(g)
    
    # grep(g,'error')
    
    # tail -f a.txt |grep 'error' |grep '404'
    
    # g1=tail('a.txt')
    # g2=grep(g1,'error')
    # g3=grep(g2,'404')
    # for i in g3:
    #     print(i)
    View Code
    4   for循环
      for循环的本质:循环所有对象,全都是使用迭代器协议

    Tips:(字符串,列表,元组,字典,集合,文件对象)这些都不是可迭代对象,只不过在for循环式,调用了他们内部的__iter__方法,把他们变成了可迭代对象,

    然后for循环调用可迭代对象的__next__方法去取值,而且for循环会捕捉StopIteration异常,以终止迭代.

       StopIteration异常:.__nex___执行后如果没有返回值就会报此异常。

    for item in g: 
        print(item)
    
     ###for执行in后面的对象g下面的.__iter__方法,得到一个迭代器k,然后for循环自动k.__next__一次,将得到的结果赋值给item.然后再iter一次变成迭代器赋值给item,直到没有值输出,出现stopiteration异常,for循环可以捕捉到这个异常,然后终止这个循环。

    for item in 8:
      print(item)
    ============结果================
    TypeError:'int' object is not iterable ###数字是不可迭代对象,下面没有.__iter__方法,所以报错。

    Try 可检测异常:

    l={'a':1,'x':2,'w':3,'z':4}
    l=l.__iter__()    #转换成迭代器
    while True:
        try:     #捕捉异常,检测其下缩进的语句是否有异常
            i=l.__next__()
            print(i)
        except StopIteration:   #except检测异常
            break
    View Code

     

    二:生成器(生成器的本质就是迭代器)

    1.什么是生成器

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

      按照我们之前所说的,迭代器必须满足两个条件:既有__iter__(),又有__next__()方法。那么生成器是否也有这两个方法呢?答案是,YES。具体来通过以下代码来看看。

    def func():
        print("one------------->")
        yield 1
        print("two------------->")
        yield 2
        print("three----------->")
        yield 3
        print("four------------>")
        yield 4
    
    print(hasattr(func(),'__next__'))
    print(hasattr(func(),'__iter__'))
    
    #########输出结果###########
    True
    True
    View Code

    Python有两种不同的方式提供生成器:

      1.函数体内包含有yield关键字,该函数的执行结果是生成器(generator).但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行.

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

    既然生成器就是迭代器,那么我们是不是也可以通过for循环来遍历出生成器中的内容呢?看下面代码.

    def func():
        print("one------------->")
        yield 1
        print("two------------->")
        yield 2
        print("three----------->")
        yield 3
        print("four------------>")
        yield 4
    
    for i in func():
        print(i)
    
    #########输出结果########
    one------------->
    1
    two------------->
    2
    three----------->
    3
    four------------>
    4
    View Code

    很显然,生成器也可以通过for循环来遍历出其中的内容。

    下面我们来看看生成器函数执行流程:

    def func():
        print("one------------->")
        yield 1
        print("two------------->")
        yield 2
        print("three----------->")
        yield 3
        print("four------------>")
        yield 4
    
    
    g = func()  #  生成器 == 迭代器
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    View Code

    每次调用g.__next__()就回去函数内部找yield关键字,如果找得到就输出yield后面的值并且返回;如果没有找到,就会报出异常。上述代码中如果在调用g.__next__()就会报错。Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果。这也是生成器的主要好处。

     生成器就是迭代器,只能前进不能后退,我们看下这个例子:

    #生成器函数补充
    # def countdown(n):
    #     while n > 0:
    #         yield n
    #         n-=1
    #
    # g=countdown(5)
    # print(g.__next__())
    # print(g.__next__())
    #
    # print('='*20)
    # for i in g:
    #     print(i)
    #
    # print('*'*20)
    # for i in g:
    #     print(i)
    
    =======结果========
    5
    4
    ====================
    3
    2
    1
    ********************
    View Code

    yiled与return的区别:

    一个标准:
      yield和return相似但是一个函数内可以有多个yield而函数中出现了多个return也只会对第一个return有效果
    yield的功能:
      1. 与return类似,都可以返回值,不一样在于,yield可以返回多个值而且可暂停,再次执行可继续下一步操作,return到了就停止不在继续运行。
      2.为封装好的的函数能够使用__iter__和__next__方法,
      3.遵循迭代器的取值方式obj.__next__(),触发函数的执行和函数的保存都是通过yeild保存的
     
    =========================================================================================================================================
    1.三元表达式
    x=2
    y=3
    
    # if x > y:
    #     print(x)
    # else:
    #     print(y)
    
    # res='aaaaa' if x > y else 'bbbbbbb'   #三元表达式---->【 条件成立     条件  条件不成立】
    #
    # print(res)
    View Code

    2.列表解析<不能加else,条件成立的情况下放到左边。>

    # l=[1,31,73,84,57,22]
    # l_new=[]
    # for i in l:
    #     if i > 50:
    #         l_new.append(i)
    # print(l_new)
    #列表解析
    # res=[i for i in l if i > 50]
    # print(res)
    View Code

    3.生成器表达式

    #g=(i for i in range(100000000000000000000000000000))
    #print (g)
    
    #print(next(g))   ##next(g) == g.__next__()
    #print(next(g))   ##next(g) == g.__next__()
  • 相关阅读:
    windows运行shell脚本
    Android Webview H5资源本地化
    Vscode开发Python环境安装
    Vscode开发Java环境搭建
    为什么索引可以提高效率?
    Java内存模型
    栈和队列----向有序的环形单链表中插入新节点
    栈和队列----单链表的选择排序
    栈和队列----将搜索二叉树转换成双向链表
    栈和队列----在单链表中删除指定值的节点
  • 原文地址:https://www.cnblogs.com/junxiansheng/p/7028084.html
Copyright © 2020-2023  润新知