zoukankan      html  css  js  c++  java
  • 迭代器和生成器

    迭代器

    容器类型:list /  tuple / dict /set

    容器类型取值方法

    例:列表

    #列表
    #第一种方法:利用索引
    l = [1,2,3,4]
    print(l[0]) # 利用索引
    print(l[:2])# 所有切片都相当于把一段内容取出来放在一个新列表中
    print(l[:]) # 生成了一个新的列表,默认浅拷贝
    
    # 所有的切片,都拷贝第一层, 对于没有嵌套的列表来说,切片就相当于深拷贝
    
    #第二种:for循环
    l = [1,2,3,4]
    for i in l:
        print(i)
    
    当需要对某一个列表中的每一个元素都需要的时候才用for循环
    View Code

    例:字典

    dic = {'name':'wanglan','age':18}
    #第一种方法:key
    print(dic['name'])
    print(dic['age'])
    # #第二种方法:for循环
    for k,v in dic.items():
        print(k,v)
    
    for k in dic:             
        if  k == "name":
            print(dic[k])
    View Code

    整型

    for i in 10:
        print(i)
    
    结果:
        for i in 10:
    TypeError: 'int' object is not iterable

    报错:int类型不是一个iterable ,iterable表示可迭代的,说明整型不能迭代,可用使用dir()来查看数据类型是否可以迭代

    print(dir([])) #判断列表
    print(dir(())) #判断元组
    print(dir(123)) #判断整型  :整型的内部不含有__iter__
    
    如果输出内容函数__iter__方法,说明该数据类型是可迭代的
    View Code

    可迭代协议 : 只要是含有'__iter__' 方法的数据类型都是可迭代的

    检查某个变量或值是不是可迭代的

    #第一种检测方法
    print('__iter__' in dir([]))
    print('__iter__' in dir(123))
    #结果:
    True
    False
    
    #第二种检测方法
    from collections import Iterable
    print(isinstance([],Iterable))   # 内置函数,判断一个具体的值是不是某个数据类型的
    print(isinstance(123,Iterable))
    
    #结果:
    True
    False
    View Code

    可以迭代的都是可以使用for循环的

    l = [1,2,3,4]
    res = l.__iter__()
    print(res)
    
    结果:
    <list_iterator object at 0x00000000025D80F0>  # iterator : 迭代器

    迭代器和可迭代的区别

    l = [1,2,3,4]
    res = l.__iter__()
    print(dir(res))
    print(dir(l))
    print(set(dir(res)) - set(dir(l)))  #在 res 中,但是不在 l 中的所以方法
     
    结果:
    ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    {'__length_hint__', '__setstate__', '__next__'}  #区别在此
    View Code

    __length_hint__ :查看迭代器中有多少个元素()

    l = [1,2,3,4]
    res = l.__iter__()
    print(res.__length_hint__())  
    
    结果:
    4
    View Code

    __setstate__ :控制迭代器从哪儿开始迭代

    l = [1,2,3,4]
    res = l.__iter__()
    res.__setstate__(2)
    for i in res:
        print(i)
    结果:
    3
    4
    View Code

    __next__:从迭代器中取下一个值

    l = [1,2,3,4]
    res = l.__iter__()
    print(res.__next__())
    print(res.__next__())
    print(res.__next__())
    print(res.__next__())
    
    结果:
    1
    2
    3
    4
    View Code

    用迭代器的next方法来写一个不依赖for的遍历

    l = [1,2,3,4]
    l_iter = l.__iter__()
    item = l_iter.__next__()
    print(item)
    item = l_iter.__next__()
    print(item)
    item = l_iter.__next__()
    print(item)
    item = l_iter.__next__()
    print(item)
    item = l_iter.__next__()
    print(item)
    
    结果:
       item = l_iter.__next__()
    StopIteration
    1
    2
    3
    4
    View Code

    这段代码会报错,因为一直取next取到迭代器没有元素了,就会抛出StopIteration

    使用异常处理机制来处理异常

    l = [1,2,3,4]
    l_iter = l.__iter__()
    while True:
        try:
            item = l_iter.__next__()
            print(item)
        except StopIteration:
            break
    View Code

    迭代器协议 : 含有__next__和__iter__方法的变量/值都是迭代器

    迭代器的特点:
      具有next和iter方法
      通过一个next多次执行就可以获得所有这个容器中的值
      迭代器中的值只能取一次
      不取的时候值不出现

    for 循环取值:
      for循环内部的机制就是迭代器取值的机制
      在for循环执行的过程中 : 先把可迭代的变成一个迭代器,然后再从中一个一个的取值

    本质上for循环替我们做的操作:
        1.生成迭代器
        2.循环每一次对这个迭代器执行next
        3.并且到迭代器的最后就停止

    迭代器的作用就是节省内存,for循环就是利用了迭代器节省内存的特点来对python当中的变量来进行操作的

    l = [1,2,3,4]
    res1 = l.__iter__()
    res2 = l.__iter__()
    # res1和res2都是迭代器
    # 是两个完全不同的迭代器
    View Code
    l = [1,2,3,4]
    res1 = l.__iter__()
    res2 = l.__iter__()
    
    for i in res1:
        print(i)
    print('**')
    
    for i in res1:
        print(i)
    print('--')
    
    结果:
    1
    2
    3
    4
    **
    --
    View Code

    第二个for循环并没有打印,因为for循环内部的机制就是迭代器取值的机制,每个迭代器都只能取值一次

    创建一个迭代器,循环这个迭代器,每次执行iter方法就创建一个迭代器,

    l = [1,2,3,4]
    
    for i in l.__iter__(): 
        print(i)
    print('^^')
    for i in l.__iter__():
        print(i)
    结果:
    1
    2
    3
    4
    ^^
    1
    2
    3
    4
    View Code

    用while循环实现一个for循环的功能(循环list/dict)

    l = [1,2,3,5,6,7,12,23,412]
    l_iter = l.__iter__()
    count = 0
    while count < len(l):
        try:   # 要保护的代码
            print(l_iter.__next__())
        except StopIteration:  # 要保护的代码中一旦出现了StopIteration错误,程序不报错,直接执行break
            break
        count +=1
    View Code

     生成器

    迭代器有两种:

    一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存。
    如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器

    生成器函数:

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

    本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

    特点:惰性运算,开发者自定义

    定义:

     一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

    定义一个生成器

    def func():
        print('hello')
        yield 1
    a = func()   #调用生成器函数,调用不会执行这个函数,而是返回一个生成器,a是一个生成器
    g = a.__next__() #执行一次
    print(g)
    View Code
    def func():
        print('hello')
        yield 1
        print('world')
        yield 2
    
    g = func()
    a = g.__next__()
    print(a)
    b = g.__next__()
    print(b)
    View Code

    yield关键字的特点: 可以记录当前函数中执行的位置,下一次继续执行,需要next来触发这个函数继续向下执行

    next和yield是一对搭档 : next开始函数的执行 yield停止函数的执行

    生成器函数和其他函数[在本质上]我们得到的结果是相同的,只不过中间的过程不同

    普通函数:必须得到所有结果之后才返回

    生成器函数:可以一边计算结果一边返回

    迭代器:

    可迭代协议 : 某个变量中含有__iter__方法,这个变量可迭代
         迭代器协议 : 某个变量中含有__iter__和__next__方法,这个变量是迭代器
         迭代器和可迭代的关系:
             迭代器一定可迭代反之不成立
         迭代器的特点 :
             节省内存
             惰性运算
             只能取一次
             只能按照顺序取
         for循环和迭代器之间的关系
             如果是非迭代器,for循环会帮助我们把这个飞迭代器编程迭代器(通过iter方法)
             帮助我们执行next方法从迭代器中取值
             帮助我们处理异常停止迭代

    生成器

    生成器就是迭代器
         我们怎么获得生成器??
             生成器函数
             生成器表达式
         什么是生成器函数?
             含有yield方法
         生成器函数有什么特点?
             调用的时候不执行
             返回一个生成器/迭代器
             从生成器中取值的方式和迭代器一样

    例:

    def produce():
        """生产衣服"""
        for i in range(2000000):
            yield "生产了第%s件衣服"%i
    
    product_g = produce()
    print(product_g.__next__()) #要一件衣服
    print(product_g.__next__()) #再要一件衣服
    print(product_g.__next__()) #再要一件衣服
    num = 0
    for i in product_g:         #要一批衣服,比如5件
        print(i)
        num +=1
        if num == 5:
            break
    
    结果:
    生产了第0件衣服
    生产了第1件衣服
    生产了第2件衣服
    生产了第3件衣服
    生产了第4件衣服
    生产了第5件衣服
    生产了第6件衣服
    生产了第7件衣服
    View Code

    监听文件的输入,对于文件中随时输入的内容进行自动化分析/自动化展示

    def get_line():
        f = open('file',encoding='utf-8')
        while True:
            line = f.readline().strip()
            if line:
                yield line.strip()
    
    line_g = get_line()
    
    for line in line_g:
        print(line.split(','))
    View Code

    send

    def func():
        print('草莓')
        yield 1
        print('香蕉味')
        yield 2
        print('榴莲')
        yield 3
    g = func()
    for i in g:
        print(i)
    # 拆开for循环
    # n = g.__next__()
    # print(n)
    # n = g.__next__()
    # print(n)
    # n = g.__next__()
    # print(n)
    
    # send
    def func():
        print('草莓')
        wl = yield 1
        print(wl)
        yield 2
        print('榴莲')
        yield 3
    g = func()
    print(g.__next__()) #开头必须是__next__
    print(g.send('香蕉')) #相当于g.__next__,只不过传入一个值进去
    View Code

    计算移动平均值

    def fun():
        sum_n = 0
        count = 0
        while True:
            if count:
                num = yield sum_n/count #9 返回 4.0
            else:   # 2
                num = yield 0  #3 返回 0  # 6 num = 4 
            sum_n +=num  #7 sum_n = 4
            count +=1 #8 count = 1 
    g = fun()
    avg = g.__next__()    # 1
    print(avg)  #4 0
    avg = g.send(4) # 5 传入4 #10 返回4
    print(avg) ##11 4.0
    avg = g.send(5)
    print(avg)
    avg = g.send(6)
    print(avg)
    View Code

    yield form

    def func():
        l1 = [1,2,3]
        s2 = 'abc'
        yield from l1 #yield form 后面直接跟可迭代变量
        yield from s2
    g = func()
    for i in g:
        print(i)
    View Code

    其他

    def func():
        lst = [1,2,3,4,5]
        return lst   #[1,2,3,4,5]
    #lst = func()
    for i in func():
        print(i)
    def func():
        lst = [1,2,3,4,5]
        for num in lst:
            yield num
        #相当于
        # num = 1
        # yield num
        # num = 2
        # yield num
        # num = 3
        # yield num
        # num = 4
        # yield num
        # num = 5
        # yield num
    
    #g = func() #生成器函数的返回值是一个生成器,生成器的本质是迭代器,g是一个生成器/迭代器
    for i in func(): # g 和 func 是相同的
        print(i) #for 循环是通过迭代器实现的
    #相当于
    # print(g.__next__()) # 1 从生成器中,通过next取到的值才是yield的返回值
    # print(g.__next__()) # 2
    # print(g.__next__()) # 3
    # print(g.__next__()) # 4
    # print(g.__next__()) # 5

    在python2.x中: range() 列表   xrange():生成器

    在python3.x中:range() 可迭代的,既不是生成器也不是迭代器

  • 相关阅读:
    列表去重
    Python中操作SQLAlchemy,SQLAlchemy中文技术文档
    gunicorn部署Flask服务
    Asset Catalog Help (十一)---Removing Images and Sets
    Asset Catalog Help (十)---Specifying a Resizable Area of an Image
    Asset Catalog Help (九)---Changing Image Set Names
    Asset Catalog Help (八)---Customizing Image Sets for Devices
    Asset Catalog Help (七)---Customizing Image Sets for Size Classes
    Asset Catalog Help (六)---Adding OS X Icons
    Asset Catalog Help (五)---Migrating an iOS App Icon Set or Launch Image Set
  • 原文地址:https://www.cnblogs.com/wanglan/p/9910209.html
Copyright © 2011-2022 走看看