zoukankan      html  css  js  c++  java
  • python学习 day13 迭代器,生成器,枚举对象

    一、复习

    1.闭包:定义在函数内部的函数(被函数嵌套的函数)
    2.装饰器:闭包的一个应用场景
        -- 为一个函数添加新功能的工具
    3.开放封闭原则:不能修改源代码,不能修改调用方式,但可以对外提供增加新功能的特性
    View Code

    小点:多个装饰器运行流程

    def o1(func):
        def inner(*args, **kwargs):
            print('o1 ------------')  # 1
            result = func(*args, **kwargs)
            print('o1 ============')  # 5
            return result
        return inner
    
    def o2(func):
        def inner(*args, **kwargs):
            print('o2 ------------')  # 2
            result = func(*args, **kwargs)
            print('o2 ============')  # 4
            return result
        return inner
    @o1
    @o2
    def fn2():
        print('fn2 ============')  # 3
    fn2()  # 函数调用位置
    # # 执行流程:函数调用位置 => o1装饰器inner => o2装饰器inner => 本体fn2
    # #  => 回到o2装饰器inner =>回到o1装饰器inner => 回到函数调用位置
    
    ##可通过debug走一遍看具体流程
    View Code
    def wrap1(func):
        print('1')
        def inner1():
            print('4')
            func()    # 应该是自身的func
            print('6')
        return inner1
    
    def wrap2(func):
        print('2')
        def inner2():
            print('3')
            func()   # 此处的func 是 inner1 即,运行 inner1()  等到上述执行完后在继续执行
            print('7')
        return inner2
    @wrap2      # func = wrap1()  执行返回inner1  即 func=inner1
    @wrap1      # func = wrap2() 执行返回inner()  即 inner1 = inner2
    def func():
        print('5')
    
    func()  # 实际运行 inner2()
    
    #打印结果: 1,2,3,4,5,6,7
    def wrap1(func):
        print('2')
        def inner1():
            print('3')
            func()    # 此处的func是 inner2,即运行inner2()
            print('7')
        return inner1
    
    def wrap2(func):
        print('1')
        def inner2():
            print('4')
            func()   # 此处为自身
            print('6')
        return inner2
    @wrap1   # func = wrap1()  执行返回inner1  本质上是 inner2 = inner1
    @wrap2    # func = wrap2() 先执行返回inner2  即 func = inner2  代码的解释顺序决定的
    def func():
        print('5')
    
    func()  #   func = inner2  而inner2=innser1 实际运行 inner1()
    
    #打印结果: 1,2,3,4,5,6,7
    上述的差异,在于谁先给函数装饰,结果如上,逻辑暂没弄清

    小点:多层嵌套的装饰器

    def wrap(var):
        def outer(func):  # outer的参数是固定的,就是被装饰的函数对象
            print(var)
            def inner(*args, **kwargs):
                print(111111111111111)
                func(*args, **kwargs)
                print(333333333333333)
            return inner
        return outer
    
    # 1.调用wrap返回outer
    @wrap(0)  # wrap(000) => outer => @outer => fn3 = outer(fn3)
    ##@wrap(0)   可看做是两种情况综合  先wrap(0),运行返回outer,
    ##                 此时在运行@outer,接下来的是正常的装饰器节奏
    
    def fn3():
        print(222222222222222)  #调用outer传入fn3返回inner给fn3
    fn3()
    
    # # @wrap(000)  # wrap(000) => outer => @outer => fn3 = outer(fn3)
    
    # # 3.调用fn3就是调用inner,在inner内部调用原fn3
    View Code

    二、迭代器

    1、相关概念:

    器:包含多个值得容器

    迭代:循环反馈(一次从容器中取出一个值)

    迭代器:从装有多个值的容器里取出一个值给外界

    迭代器:从装有多个值得容器中一次取出一个值给外界

    2、可迭代对象

    对象:python中装有地址的一个变量

    可迭代对象:该对象有_iter_()方法

    可迭代对象通过调用_iter_()方法得到迭代器对象

    3、迭代器对象

    迭代器对象可以做到不依赖索引取值(一次从容器中取出一个值)

    迭代器对象都存在_next_()方法,且通过该方法获取容器中的值,获取规则,从前往后一次一个

    st1={3,2,6,5,9}   #不清楚集合为什么打印的结果是从小到大,而其他不是
    iter_obj=st1._iter_()
    print(iter_obj)     #<set_iterator object at 0x00000000021E13A8>
    
    #迭代器对象取一个值就少一个值(重点掌握)
    print(iter_obj.__next__())  # 2
    print(iter_obj.__next__())  # 3
    print(iter_obj.__next__())  # 5
    print(iter_obj.__next__())  # 6
    print(iter_obj.__next__())  # 9
    
     #print(iter_obj.__next__()) #再加上一个,超出其范围,会报错
                                                                          StopIteration
    
    ter_obj=st1._iter_() #若不加上这个迭代器对象,会输出结果为空,上面
                                                                              已经取完其值
    while True:
        try:                                               
            ele = iter_obj.__next__()
            print(ele)
        except StopIteration:     # 此处的try except 用来除去异常
            # print("取完了")        # 因为会存在无限循环,但是值不够的情况
            break
    View Code

    4、for 循环

    自带异常处理的while循环,自动获取被迭代对象的迭代器对象(即不需要人为添加._next_())

    # for循环迭代器:
    # -- 1.自动获取被迭代对象的迭代器对象;
    # -- 2.在内部一次一次调用__next__()方法取值;
    # -- 3.自动完成异常处理
    for v in obj:
    print(v)
    if v == 2:
    break


    print(obj.__iter__().__iter__().__iter__().__next__()) # 3 因为上面的for已经取了两个值
    # print(obj.__iter__().__iter__().__iter__() is obj) # True
    # 可迭代对象.__iter__()得到的是该对象的迭代器对象
    # 迭代器对象.__iter__().__iter__()得到的就是迭代器对象本身

    迭代器对象代码:

    for v in 'abc'.__iter__():
        print(v)
    结果:
    a
    b
    c
    
    for v in 'abc'.__iter__():
        print(v)
    结果:
    a
    b
    c
    # 为什么此处可以重复打印?  因为第二次重新给字符串装换到了迭代器对象
    因此可以重复使用,而不是上面取完值后,下面没有输出结果
    View Code
    with open('abc.txt', 'r', encoding='utf-8') as f:
        print(f.__next__())
        print(f.__next__())
        print(f.__next__())
    
    
    
    #‘abc.txt’文件里存在多行数据,此时的print是一行打印一次,因此需要多个print
    View Code

    直接:

    可迭代对象:即有有__iter__()方法的对象,调用该方法返回迭代器对象

      str | list | tuple | dict | set | range() | file | 迭代器对象 | enumerate() | 生成器

    迭代器对象:有__next__()方法的对象,也就是用该方法一次从迭代器对象中获取一个值,取出一个少一个

    file | enumerate() | 生成器

    重点:
    1.从迭代器对象中取元素,取一个少一个,如果要从头开始去,需要重新获得拥有所有元素的迭代器对象
    2.迭代器对象也有__iter__()方法,调用后得到的是自己本身(当前含义几个元素,得到的就只有几个元素的迭代器对象)

    3、对于for循环迭代:

         1.自动获取被迭代对象的迭代器对象
         2.在内部一次一次调用__next__()方法取值;
         3.自动完成异常处理

    三、生成器

    # 生成器:就是一个迭代器对象
    # 包含yield关键字的函数就是生成器
    # 该函数名()得到的是生成器对象,且不会执行函数体
    # 在函数内部执行一次,在遇到下一个yield时停止,且可以拿到yield的返回值
    def my_yield():
     print('first')
     yield 1
     print('second')
     yield 2
     print('Third')
     yield 3
    g=my_yield()
    
    next(g)    
    next(g)
    next(g)
    #以下为结果:   只打印函数体
    first
    second
    Third
    
    print(next(g)
    print(next(g)
    print(next(g)
    #以下为结果:  函数体和返回值都打印
    first
    1
    second
    2
    Third
    3
    打印生成器的结果1
    def my_yield():
     print('first')
     yield 1
     print('second')
     yield 2
     print('Third')
     yield 3
    
    
    for i in my_yield():
        print(i)
    
    #下面为结果:
    first
    1
    second
    2
    Third
    3
    
    
    yields=my_yield()
    print(yields)
    #以下为结果:
    <generator object my_yield at 0x000000000216A390>
    
    
    
    yields=my_yield()
    print(list(yields))
    #以下为结果:
    first
    second
    Third
    [1, 2, 3]
    打印生成器的结果2
    总结:
    按 顺序打印函数体和返回值:
    for 循环       print(next(i))
    
    先打印函数体后打印返回值:
    print(list(i))   用其他类型数据转换
    
    直接打印函数体:
    next(i)
    
    直接打印生成器地址:
    print(i)
    
    
    建议日常使用for循环和next方式取值
    生成器打印结果总结


    四‘枚举对象 ’
    enumerate
    通过for迭代器 循环遍历 可迭代对象,需要知道迭代的索引
    #从上一次停止的位置紧着往下走,在再遇到下一个yield时停止,且可以拿到yield的返回值
    # 生成器可以被for循环迭代
    ls = [1, 3, 5, 7, 9]
    for i, v in enumerate(ls):
    print(i, v)
    结果:

    0 1
    1 3
    2 5
    3 7

    4 9

    小点:
    dict={'a':1,'b':2}
    lis=[]
    for i in enumerate(dict):
        lis.append(i)
    print(lis)
    #[(0, 'a'), (1, 'b')]
    
    #此处可见 仅用一个值i就可将索引与对应的值导出
    #可利用此种特性将数据成行打印
    
    #也可利用两个参数,将其换行打印
    

      

  • 相关阅读:
    范仁义css3课程---7、文本样式2
    android图片缓存框架Android-Universal-Image-Loader(二)
    Android 开源框架Universal-Image-Loader完全解析(三)---源代码解读
    憨人 音译
    Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用
    Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解
    Android开发
    87狂热
    迟志强
    翟惠民
  • 原文地址:https://www.cnblogs.com/changwenjun-666/p/10651112.html
Copyright © 2011-2022 走看看