• Python基础--迭代器和生成器


    一、迭代器

    迭代器的特性:
    
        迭代是Python中最强有力的特性之一,可以把迭代看成是一种处理序列中元素的方式。
    
        可以直接作用于for循环的对象统称为可迭代对象(Iterable)。
    
        可以被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator)。
        
        所有的Iterable均可以通过内置函数iter()来转变为Iterator。
    
        出可迭代对象的个数会报错StopIteration,是一个结束信号
    
    迭代器的优点:
        
        1、迭代器提供一种不依赖于索引的取值方式,这样就可以遍历那些没有索引的对象了(字典、集合、文件)
        2、迭代器和列表比较,迭代器是惰性计算,更节约内存
    
    迭代器的缺点:
        1、永远不能获取迭代器的长度,使用不如列表索引取值灵活
        2、一次性的,只能往后取值,不能往前,不能像索引一样取得指定位置的值
    

    二、查看可迭代和迭代器的方法

        from collections import Iterable,Iterator
            s='hello'
            l=[1,2,3]
            t=(1,2,3)
            d={'a':1}
            set1={1,2,3,4}
            f=open('a.txt')
    
            #都是可迭代,只要对象有__iter__()方法,都是可迭代的
            s.__iter__()
            l.__iter__()
            t.__iter__()
            d.__iter__()
            set1.__iter__()
            f.__iter__()
                   
            #查看是否可以迭代的
            print(isinstance(s,Iterable))
    
            #查看是否是迭代器,只有文件是迭代器
            f.__next__()
    
            print(isinstance(f,Iterator))
            
            
    

    三、手动访问迭代器中的元素

    1、问题

    我们要处理某个可迭代对象中的元素,但是基于某种原因不能也不想使用for循环。
    

    2、解决方案

    要手动访问可迭代对象中的元素,可以使用next()函数,然后自己编写代码来捕获stopiteration异常。例如:
    
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    with open('passwd','r',encoding='utf8') as f:
        while True:
            try:
                line=next(f)
                print(line,end='')
            except StopIteration:
                break
    #一般来说,stopiteration异常是用来通知我们迭代结束的,但是,如果是手动执行next(),也可以命令他返回一个值,比如None,示例如下:
    
    
    with open('passwd','r',encoding='utf8') as f:
        while True:
            line=next(f,None)
            if line is None:
                break
            print(line,end='')
    
    
    大多数情况下,我们会用for循环来访问可迭代对象中的元素,但是,偶尔也会碰到需要对底层迭代机制做更精细情况的控制。因此,了解迭代实际发生了些什么是很有必要的。for 循环也是先使用iter方法把要循环的对象生成一个迭代器,然后去遍历这个迭代器,遍历迭代器里的每个元素
    
    >>> items=[1,2,3]
    >>> i=iter(items)     #===> i.__iter__()
    >>> next(i)           #===> i.__next__()
    1
    >>> next(i)
    2
    >>> next(i)
    3
    >>> next(i)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    
    

    四、生成器

      生成器是一个包含yield关键字的函数,当它被调用时,在函数中的代码不会执行,而会返回一个迭代器。每次请求一个值,就会执行生成器中的代码,直到遇到一个yield或者return语句,yield语句一位着会生成一个值,return语句一位着生成器要停止执行(不在生成任何东西,return语句只有在一个生成器中使用时才能进行无参数调用)换句话说,生成器是由两部分组成:生成器的函数和生成器的迭代器,生成器的函数使用def定义,包括yield部分,生成器的迭代器是这个函数返回的部分。
    
    def countdown(n):
        print('starting to count from',n)
        while n>0:
            yield n
            n-=1
        print('Done!')
    g=countdown(5)
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    
    #执行结果如下
    starting to count from 5
    5
    4
    3
    2
    1
    
    #函数中出现了yield语句,就会把这个函数转换成生成器。与普通的函数不同,生成器只会在响应迭代操作是才会运行。调用时需要使用next方法才能执行,没执行一次,当遇到下一个yield时就会停止,下次执行next时,将从当前yield往下执行,知道遇到一个yield
    
    生成器的本质就是一个迭代器,同时也是一个函数,调用的方式和函数类似,yield也相当于函数中的return
        yield和return的区别:return只能返回一次函数就会彻底结束,而yield能返回多次值
    yield到底干了什么事情:
        1、yield把函数变成生成器(迭代器),把iter和next方法封装在函数内部
        2、函数在暂停一及继续下一次运行时的状态是yield保存
    

    五、协程

    from urllib.request import urlopen
    def init(func):
        def wrapper(*args,**kwargs):
            res=func(*args,**kwargs)
            next(res)
            return res
        return wrapper
    
    @init
    def get():
        while True:
            url=yield
            res=urlopen(url).read()
            print(res)
    
    g=get()  #g是一个迭代器
    # next(g) #这里使用一个init的装饰器,自动做了next的工作
    g.send("http://www.baidu.com")     #使用send把括号内的URL传递给yield
    g.send('http://www.python.org')
    g.send('http://www.163.com')
    
    协程函数,是把yield改为表达式的方式,改过send代替next给yield传值
    e.send于next(e)的区别
        1、如果函数内yield是表达式形式,那么必须先next(e),让生成器在第一个yield位置处等着
        2、二者的共同之处都可以让函数在上次暂停的位置继续运行,不一样的地方在于,send在触发一下次代码的执行时,给yield传值
    
  • 相关阅读:
    linux & xp 双系统 重装的问题
    判断推理类试题的复言命题考点与题型总结
    Oracle、MySQL、SQL Server数据库的数据类型的差异
    java环境变量设置和问题及解决方法
    如何正确卸载MySQL,主要是删除注册表中的垃圾信息
    J2EE经典面试题及答案
    正则表达式
    囚犯的两难处境
    MySQL 数值数据类型
    linux学习之SHELL脚本
  • 原文地址:https://www.cnblogs.com/baomanji/p/6701975.html
Copyright © 2020-2023  润新知