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

    一.认识迭代器:  

    迭代器:
    器:工具
    迭代:重复(更新换代)的过程,这种过程每次迭代都是基于上一次的结果
    迭代器:迭代取值的工具

    为什么用迭代器:
    迭代提供了一种不依赖于索引取值的方法

    优点;
    1.可以不依赖索引取值
    2.值占用一份内存空间,不会内存溢出 (python3与python2区别)
    缺点:
    1.不能去指定的元素
    2.取完值会报错 StopIteration
     
    n = 0
    while True:
        print(n)
    不算迭代器 没有迭代
    
    n = 0
    while True:
        print(n)
        n += 1
    是迭代器 有迭代 + 重复

    二.可迭代对象与迭代器对象

    可迭代对象:
    内置有__iter__方法的都是可迭代对象 . __iter__ 也可以写成 iter()
    str,list,tuple,dict,set,file
    迭代器对象:
    内置有__iter__方法,__next__方法是迭代器对象. __next__ 迭代器取值
    file

    可迭代对象使用__iter__方法就得到该对象的迭代器对象
    迭代器对象一定是可迭代对象,可迭代对象不一定是迭代器对象
     
    可迭代对象转迭代器对象 __iter__
    
    s = 'hello'
    res = s.__iter__()
    print(res)  # 得到的是迭代器对象的内存地址
    # >>> <str_iterator object at 0x0000027734C7E908>
    
    
    调用 __next__ 迭代取值
    l = [1,2,3]
    res = l.__iter__()
    print(res.__next__())  # >>> 1
    print(res.__next__())  # >>> 2
    print(res.__next__())  # >>> 3
    print(res.__next__())  # >>> 值取完,报错 StopIteration
    
    d = {'name':'waller','age':20,'hobby':'read'}
    res = d.__iter__()
    print(res.__next__())  # >>> name
    print(res.__next__())  # >>> age
    print(res.__next__())  # >>> hobby
    print(res.__next__())  # >>> 值取完,报错 StopIteration
    
    print(d.__iter__().__next__())  # >>> name
    print(d.__iter__().__next__())  # >>> name
    print(d.__iter__().__next__())  # >>> name
    # 可迭代对象转成迭代器对象后取值,又重新把可迭代对象转成迭代器对象再取值,所以取的都是第一个值
    
    # 文件本身就是迭代器对象,无论调用多少个__iter__ 都是一样的结果
    with open('file.txt','r',encoding='utf-8') as f:
        pass
    f_iter = f.__iter__()
    print(f_iter is f)  # True 文件对象调用__iter__方法后的内存地址和调用前一样
    f.__next__()  # 迭代器对象用__next__取文件里每行的内容
    
    
    异常处理
    d = {'name':'waller','age':20,'hobby':'read'}
    res = d.__iter__()
    
    while True:
        try:
            print(res.__next__())
        except StopIteration:
            print('值已取完')
            break
    # 对迭代器对象循环取值,通过try + except StopIteration 截获到住取完时的报错信息,结束循环,就不会报错
    
     

     

     三.for循环的本质

    for循环本质:
    1.现将 in 后面的可迭代对象调用__iter__方法转成迭代器对象
    2.再调用__next__方法 迭代取值
    3.内部有异常捕获,当值取完,出现 StopIteration ,自动结束循环
    迭代取值的本质就是for循环
    问: 文件本身就是迭代器对象,为什么还会有__iter__方法?
    因为迭代取值的本质是for循环,for循环第一步是将in后面的可迭代对象调用__iter__方法转成迭代器对象,
    文件也是通过for循环取值,要经理for循环取值的第一步,所以文件有__iter__方法,但不会改变文件
    l = [1,2,3]
    for i in l:
        print(i)
    
    res = l.__iter__()
    print(res.__next__())
    print(res.__next__())
    print(res.__next__())

    五.生成器:

    生成器:
    用户自定义的迭代器
    表达式:
      
    res =(值 for i in 可迭代对象 if 条件) (*****)
      生成器不会主动执行任何一行代码,必须通过__next__触发代码执行

    函数版生成器:
    def func(参数...):
    ...
    yield 值
    ...
    g = func()
    关于yield:
    1.函数内如果有yield关键字,那么加括号执行函数的时候并不会触发函数体代码的运行,会将函数初始化成迭代器
    2.yield后面跟的值就是调用迭代器__next__方法你能得到的值
    3.yield会将函数暂停住
    4.yield既可以返回一个值也可以返回多个值 并且多个值也是按照元组的形式返回
    5.yield支持外界为其传参(了解)

    与return之间异同点
    相同点:都可以返回值,并且都可以返回多个
    不同点:
    yield可以返回多次值,而return只能返回一次函数立即结束
    yield还可以接受外部传入的值

    生成器表达式:
    例1:
    res = (i for i in range(1,10) if i != 4) print(res) # >>> <generator object <genexpr> at 0x000002272C5B0780> print(res.__next__()) print(res.__next__()) print(res.__next__()) print(res.__next__()) 例2: #占内存 f = open('xxx.txt','r',encoding='utf-8') data = f.read() print(len(data)) f.close() with open('xxx.txt','r',encoding='utf-8') as f: # n = 0 # for line in f: # n += len(line) # print(n) g = (len(line) for line in f) # print(g.__next__()) # print(g.__next__()) # print(g.__next__()) # print(g.__next__()) print(sum(g))
    
    
    函数版生成器:
    def
    func(): print('--第一次--') yield 1 print('--第二次--') yield 2 print('--第三次--') yield 3 print('--第四次--') yield res = func() # 初始化成迭代器 print(res) print(res.__next__()) print(res.__next__()) print(res.__next__()) print(res.__next__()) ''' <generator object func at 0x000001CDAAB0A938> --第一次-- 1 --第二次-- 2 --第三次-- 3 --第四次-- None '''

    range()原理

    for i in range(1,8,2):
        print(i) # >>> 1 3 5 7
    def my_range(x,y,z=1): while x < y: yield x x += z res = my_range(1,4) # 把my_range 初始化成迭代器 print(res) # >>> <generator object my_range at 0x00000297384B0780> print(res.__next__()) # >>> 1 print(res.__next__()) # >>> 2 print(res.__next__()) # >>> 3 for i in my_range(1,8,2): print(i,end=' ') # >>> 1 3 5 7
    def dog(name):
        print('%s 准备开吃'%name)
        while True:
            food = yield
            print('%s 吃了 %s'%(name,food))
    g = dog('xx')
    g.__next__()  # 必须先将代码运行至yield 才能够为其传值
    g.send('狗不理包子')  # 给yield左边的变量传参  触发了__next__方法
    g.send('饺子')
    '''
    xx 准备开吃
    xx 吃了 狗不理包子
    xx 吃了 饺子
    
    '''
    yield支持外界为其传参(了解)
    
    

    题:

    def add(n,i):
        return n+i
    def test():
        for i in range(4):
            yield i
    g=test()  # 函数test初始化成迭代器 (不运行)
    
    for n in [1,10]:
        g=(add(n,i) for i in g)
        # 第一次for循环g=(add(n,i) for i in test()) 此时n = 1
    
        # 第二次for循环g=(add(n,i) for i in (add(n,i) for i in test())) 此时 n = 10
    # print(n)
    res=list(g)  
    
    """
    1.list是基于for循环,for循环内有__next__ 触发 g 的内部代码运行
    2.g 中的 (add(n,i) for i in test()) 先运行变成  (10+0 ,10+1,10+2,10+3) 
    3.此时变成 g = (add(n,i) for i in (10,11,12,13)  最终是 10+10,10+21,10+22,10+23
    """
    
    #A. res=[10,11,12,13]
    #B. res=[11,12,13,14]
    #C. res=[20,21,22,23]  答案
    #D. res=[21,22,23,24]










  • 相关阅读:
    Win7安装netbeans 找不到JDK
    MyEclipse10 中设置Jquery提醒,亲测可用
    Property 'submit' of object #<HTMLFormElement> is not a function
    JSP Unable to compile class for JSP
    JSP session过期时间(小记)
    JSP乱码(小记)
    JS 正则表达式基础
    CSS 盒子模型
    Cmder--window开发者神器!!
    encodeURI和encodeURIComponent两者的区别
  • 原文地址:https://www.cnblogs.com/waller/p/11189895.html
Copyright © 2011-2022 走看看