六、迭代器、生成器和装饰器

1.迭代器

  • 定义

    能被next()函数进行调用且不断返回下一个值的对象。其内置方法中包含__iter__(返回迭代器本身)和__next__(返回容器的下一个元素)。

  • 特征

    迭代器会生成惰性序列,它通过计算把值依次的返回,一边循环一边计算,而不是一次性得到所有的数据。

  • 优点

    需要数据的时候,一次取一个,可以在很大程度上节省内容空间,而不是一次性把所有的数据存入内存中;此外,可以遍历无限量的数据。

  • 创建

    使用iter()函数来创建。

    string = iter('abcd')
    print(next(string))
    print(next(string))
    print(next(string))
    print(next(string))
    # 遍历完成之后继调用
    print(next(string))
    
    # 输出结果
    StopIteration
    a
    b
    c
    d
    
    # 注意:当遍历完序列时,会引发一个StopIteration异常。使用for循环可以规避整个问题(for循环的底层使用了next方法)。
    string = iter('abcd')
    for item in string:
        print(item)
    # 输出结果
    a
    b
    c
    d

2. 生成器

  • 定义

    包含了yield语句的函数。

  • 特征

    执行生成器函数时,其内部代码不执行,而是返回一个生成器对象(特殊的迭代器)。生成器可以暂停函数并返回一个中间结果(遇到yield本次循环就终止,并返回yield后的值),可以被for循环或者用next函数逐个取值。

  • 格式

    # 格式一
    def fun():
        print('第一次执行')
        yield 1
        print('第二次执行')
        yield 2
        print('第三次执行')
        yield 3
    
    result = fun()
    print(result, type(result))
    for i in result:
        print(i)
    
    
    # 格式二
    def fun():
        print('第一次执行')
        yield 1
        print('第二次执行')
        yield 2
        print('第三次执行')
        yield 3
    
    result = fun()
    print(next(result))
    print(next(result))
    print(next(result))
    
    
    # 输出结果
    <generator object fun at 0x000001A203DD5A20> <class 'generator'>
    第一次执行
    1
    第二次执行
    2
    第三次执行
    3
  • 注意

    生成器中不能包含return语句,遇到return语句则会结束生成器。

    
    def fun():
        print('第一次执行')
        yield 1
        print('第二次执行')
        yield 2
        return 123
        print('第三次执行')
        yield 3
    
    for i in fun():
        print(i)
    
    # 输出结果
    第一次执行
    1
    第二次执行
    2
  • 生成器推导式

    result = (lambda: i ** 2 for i in range(1, 5))
    print(type(result))
    for i in result:
        print(i())
    
    # 输出结果
    <class 'generator'>
    1
    4
    9
    16
    
    
    # 对比列表推导式
    result = [lambda: i ** 2 for i in range(1, 5)]
    print(type(result))
    for i in result:
        print(i())
    
    # 输出结果
    <class 'list'>
    16
    16
    16
    16

3. 装饰器

  • 定义

    在不改变原函数内部代码的基础上,在函数执行之前和之后自动执行某个功能。

  • 装饰器编写格式

    def 外层函数(传入参数):
        def 内层函数(*args, **kwargs):
            result = 传入参数(*args, **kwargs)
            return result
        return 内层函数
  • 装饰器应用格式

    @外层函数
    def index():
        pass
    
    index()
  • 作用

    # 和index函自身相比,使用装饰器之后,执行index函数可以在原函数的基础上多执行print('执行原函数前')和print('执行原函数后')两条语句,此处是以最简单的方式来进行说明,完全可以根据需求将这两个语句换成功能更复杂的语句块。
    
    def 外层函数(传入参数):
        def 内层函数(*args, **kwargs):
            print('执行原函数前')
            result = 传入参数(*args, **kwargs) # 执行原函数并返回值
            print('执行原函数后')
            return result
        return 内层函数
    
    @外层函数
    def index():
        pass
    
    index()
  • 例子

    def fun(arg):
        def inner():
            print('执行函数前添加的功能:', 1)
            v = arg()
            print('执行函数后添加的功能:', 3)
            return v
        return inner
    
    # 第一步:执行fun函数并将下面的函数作为参数传递,相当于:fun(index)
    # 第二步:将fun的返回值重新赋值给下面的函数名,相当于:index = fun(index)
    @fun
    def index():
        print('函数自己的功能:', 2)
        return 666
    
    index()
    
    # 输出结果为
    执行函数前添加的功能: 1
    函数自己的功能: 2
    执行函数后添加的功能: 3
    
    # 若没有@fun语句(没有使用装饰器),输出结果为
    函数自己的功能: 2
  • 带参数的装饰器

    # 可以用于连续多次重复执行函数
    def with_parameter(count):
        def outer(arg):
            def inner():
                for i in range(count):
                    print('\n第%d次执行' % (i + 1))
                    print('执行函数前添加的功能:', 1)
                    v = arg()
                    print('执行函数后添加的功能:', 3)
                return v
            return inner
        return outer
    
    # 相当于:index = with_parameter(3)(index)
    @with_parameter(3)
    def index():
        print('函数自己的功能:', 2)
        return 666
    
    result = index()
    print('\n函数最后的返回结果:', result)
    
    # 输出结果
    
    第1次执行
    执行函数前添加的功能: 1
    函数自己的功能: 2
    执行函数后添加的功能: 3
    
    第2次执行
    执行函数前添加的功能: 1
    函数自己的功能: 2
    执行函数后添加的功能: 3
    
    第3次执行
    执行函数前添加的功能: 1
    函数自己的功能: 2
    执行函数后添加的功能: 3
    
    函数最后的返回结果: 666
  • 装饰器的嵌套

    def outer1(fun):
        def inner1():
            print('This is 001')
            result1 = fun()
            print('This is 002')
    
            return result1
    
        return inner1
    
    
    def outer2(fun):
        def inner2():
            print('This is 003')
            result2 = fun()
            print('This is 004')
    
            return result2
    
        return inner2
    
    
    @outer1
    @outer2
    def origin():
        print('This is initial')
    
    
    origin()
    
    # 输出结果
    This is 001
    This is 003
    This is initial
    This is 004
    This is 002
    
    '''
    逻辑法分析:
    步骤一:origin = outer2(origin),outer2(origin) == inner2
    步骤二:origin = outer1(outer2(origin)),origin = outer1(inner2),outer1(inner2) == inner1
    步骤三:执行origin()等价于inner1(),此时输出This is 001;接着执行inner2(),此时输出This is 003;然后执行origin()原函数,此时输出This is initial;origin()原函数执行完毕,接着输出This is 004;inner2()执行完毕,接着输出This is 002,至此,整个函数执行完毕。
    '''
    
    '''
    装饰器思想法分析:
    outer2是origin的装饰器,outer1又是outer2的装饰器。
    因此,在执行该嵌套装饰器时,outer1的目的是在未改变outer2的情况下,在其执行前后添加所需的功能,所以outer1的'This is 001'最先输出,接着输出outer2的内容。而outer2是origin的装饰器,所以outer2的目的是在未改变origin的情况下,在其执行前后添加所需的功能,所以outer的'This is 003'先输出,接着输出origin的'This is initial',然后输出outer2的'This is 004',最后输出outer1的'This is 002'。
    '''
    
    # 注意:多层装饰器嵌套时,按从下往上的方向执行。
posted @ 2019-11-05 23:27  雨牧  阅读(...)  评论(...编辑  收藏