zoukankan      html  css  js  c++  java
  • python基础之迭代器与生成器

      一、什么是迭代器:

      迭代是Python最强大的功能之一,是访问集合元素的一种方式。

      迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。

      迭代器是一个可以记住遍历的位置的对象。

      迭代器的特点:只能往前不会后退。

      迭代器有两个基本的方法:iter() 和 next()

        1、iter方法:返回迭代器对象本身

        2、next方法:返回迭代器的下一个元素

      可迭代的:只要对象本身有__iter__方法,那它就是可迭代的。

      字符串,列表或元组对象都可用于创建迭代器:

    list = [1,2,3,4] #list列表
    r = iter(list)用iter方法将list转成迭代器赋值给r
    print(next(r)) #用next方法使用迭代器r,并输出结果
    print(next(r)) #因为迭代器是一次性的,so,要想看下面的内容,
                           # 还得用next方法使用迭代器r,并输出结果   
    ----------------以下是输出结果--------------------
        1
        2
    

      二、迭代器的优点:

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

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

      三、迭代器的缺点:

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

        2、一次性的,只能往后取值,不能倒着取值。就像象棋里卒一样不能倒着走。

      下面来用代码展示一下吧:

      使用next需要注意的:

    d = {"a":1,"b":2,"c":3} #定义了一个字典
    r = iter(d) #用iter方法将字典转成了一个迭代器并赋值给r
    while True: #定义了一个循环
            print(next(r)) #用next调用迭代器r
    -------------------以下是输出的结果-------------------
        a   #一直循环next的话,超出了元素的个数的时候就会报错
        b
        c
        Traceback (most recent call last) #报错的内容
    

      下面介绍一个方法,使不会报错:

    d = {"a":1,"b":2,"c":3}
    r = iter(d)
    while True: #加上try之后,它会自己判断,超出后会自动break
        try:
            print(next(r))
        except StopIteration:
            break
    -------------以下是输出结果---------------
        a
        b
        c
    

      我们用for循环来试试:

    d = {"a":1,"b":2,"c":3}
    for i in d : #for循环,遍历字典的中的每一个元素
        print(i) 
    --------------以下是输出的结果--------------
        a
        b
        c
    

       总结:不难看出for的作用是遍历迭代器——对一个迭代器(实现了 __next__)或者可迭代对象(实现了 __iter__)。

      查看可迭代对象与迭代器对象:

    from collections import Iterable,Iterator #调用模块
    #以下是定义的不同数据类型
    s='hello' #字符串
    l=[1,2,3] #列表
    t=(1,2,3) #元组
    d={'a':1,'b':2} #字典
    set1={1,2,3,4} #集合
    f=open('a.txt') #文件
    
    #都是可迭代的(只有可迭代的才有iter方法)
    s.__iter__()
    l.__iter__()
    t.__iter__()
    d.__iter__()
    set1.__iter__()
    f.__iter__()
    
    #查看是否是可迭代对象(True为是,False为否)
    print(isinstance(s,Iterable))--------->True  #字符串
    print(isinstance(l,Iterable))--------->True  #列表
    print(isinstance(t,Iterable))--------->True  #元组
    print(isinstance(d,Iterable))--------->True  #字典
    print(isinstance(set1,Iterable))--------->True  #集合
    print(isinstance(f,Iterable))--------->True  #文件
    
    #查看是否是迭代器(Turn为是,False为否)
    print(isinstance(s,Iterator))--------->False  #字符串
    print(isinstance(l,Iterator))--------->False  #列表
    print(isinstance(t,Iterator))--------->False  #元组
    print(isinstance(d,Iterator))--------->False  #字典
    print(isinstance(set1,Iterator))--------->False  #集合
    print(isinstance(f,Iterator))--------->True  #文件
    

      四、生成器

      定义:

        函数内带有yield关键字,那么这个函数执行的结果就是生成器(generator)。

        跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

        在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行 next()方法时从当前位置继续运行。

      下面用实例使用 yield 实现斐波那契数列:

    def fibonacci(n): # 生成器函数 - 斐波那契
        a, b, counter = 0, 1, 0
        while True:
            if (counter > n):
                return
            yield a
            a, b = b, a + b
            counter += 1
    f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
    
    while True:
        try:
            print (next(f), end=" ")
        except StopIteration:
            break
    -----------以下是输出的结果-------------
    0 1 1 2 3 5 8 13 21 34 55 

      总结yield的功能:

        1.相当于把__iter__和__next__方法封装到函数内部

        2.与return比,return只能返回一次,而yield能返回多次

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

      生成器与return有何区别?

      return只能返回一次函数就彻底结束了,而yield能返回多次值。

      return作用:

      在一个生成器中,如果没有return,则默认执行到函数完毕;

      如果遇到return,在执行过程中 return,则直接抛出 StopIteration 终止迭代。

      yield的表达式形式:

      food = yield

    #定义阶段
    def eater(name):
        print('%s start to eat' % name)
        while True:
            food = yield
            print('%s eat %s' % (name, food))
    #调用阶段
    e = eater('egon')
    next(e)
    print(e.send("盖饭"))
    ------------------以下是输出结果---------------------
        egon start to eat
        egon eat 盖饭
    

      e.send与next(e)的区别:

        1、如果函数内yield是表达式形式,那么必须先next(e)

        2、二者的共同之处是都可以让函数在上次暂停的位置继续运行,不一样的地方在于send在触发下一次

    代码的执行时,会顺便给yield传一个值。

      实操一:

       迭代器的应用:

        实现的功能:linux命令:cat a.txt | grep apple

        要求1:定义迭代器函数cat;

        要求2:定义迭代器函数grep;

        要求3:模拟管道的功能,将cat的输出结果作为grep的输入参数

    def cat(file_path):
        '''输出a.txt里的内容'''
        with open(file_path,mode="r",encoding="utf8") as f:#打开文件a.txt
            line = f.read()#读取文件内容
            yield line #返回值line
    def grep(cho,lines):
        '''将a.txt里的内容作为参数传进来进行匹配'''
        for ab in lines: #循环a.txt
            if cho in ab: #判断输入的元素是否在a.txt里
                yield cho #在就返回值给g2
            else: #没在a.txt里面的情况
                print("33[31;1m不存在33[0m")
    g1 = cat("a.txt") #输入参数调用函数cat,并赋值给g1
    g2=grep("apple",g1) #将g1作为参数调用函数grep,并赋值给g2
    for i in g2: #相当于迭代器的next方法(next(g2))
        print("33[42;1m%s33[0m"%i) #打印输出结果
    

      实操二

      生成器的应用:

      把下述函数改成生成器的形式,执行生成器函数到一个生成器g,然后,每次g.send(url),打印页面的内容,利用g可以无限send(url)。

    def get(url): 
        def index():
            return urlopen(url).read()
        return index
    

      只用一层函数的方法:

    def get(): 
        print("开始爬虫了!")
        while True:
            url = yield #每次执行到这,都会在这等着用户的下次输入
            print(urlopen(url).read())
            print("33[31;1m完成了一次爬虫33[0m")
    g = get() #调用get函数并赋值给g
    next(g) #用next方法调用生成器get
    print(g.send("http://www.baidu.com")) #send一个网址
    print(g.send("http://www.sina.com"))#可以无限的send(url)
    -----------------------以下是输出的结果----------------------------
        开始爬虫了!
        b'<!DOCTYPE html>
    <!--STATUS OK-->
    
    
    
    
    
                  <<<<< 中间内容省略>>>>>
        d dmp -->
    
    <!-- body code end -->
    </body>
    </html>'
        完成了一次爬虫          

      用闭包函数的方法:

    #定义函数阶段
    def get():
        def index():
            print("开始爬虫了!")
            while True:
                url = yield #每次在这等着用户的输入
                print(urlopen(url).read()) #打印爬虫的结果
                print("33[31;1m完成了一次爬虫33[0m") #爬虫完毕打印
        return index #返回 index的内存地址
    #调用函数阶段
    g = get() #调用函数get,并将返回值赋值给g
    g2 = g() #将get的返回值g调用即index函数,并赋值给g2
    next(g2) #用next方法调用g2,此时会停在yield那
    print(g2.send("http://www.baidu.com")) #给url传参数
    print(g2.send("http://www.sina.com")) #可以无限的send(url)
    ---------------------------以下是输出的结果--------------------------
      开始爬虫了!
      b'<!DOCTYPE html>
    <!--STATUS OK-->
    
    
    
    
    
    
                <<<<<中间的内容省略>>>>>
      </script>
    
    
    
    </body>
    </html>
    
    
    
    
    
    '
      完成了一次爬虫
    

      

  • 相关阅读:
    DeflateStream类
    BufferedStream类
    FileStream类
    Asp.net MVC Comet 推送
    MVC 读书笔记
    MVC部署
    MVC系统过滤器、自定义过滤器
    MVC 路由规则
    MVC 模型绑定
    边双+点双模板
  • 原文地址:https://www.cnblogs.com/Michael--chen/p/6694382.html
Copyright © 2011-2022 走看看