zoukankan      html  css  js  c++  java
  • 六、迭代器、生成器和装饰器

    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('
      第%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('
      函数最后的返回结果:', 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'。
      '''
      
      # 注意:多层装饰器嵌套时,按从下往上的方向执行。
      
  • 相关阅读:
    Codeforces Round #650 (Div. 3)
    C. Count Triangles
    A National Pandemic (思维 + 树链剖分模版)
    扫描线专题
    扫描线模版
    莫队模版
    JS设计模式 -- 4种创建型模式
    滑动窗口的最大值 -- 单调队列
    JS链表实现栈和队列
    js数组扁平化的几种实现方式
  • 原文地址:https://www.cnblogs.com/aaron-zhou/p/11802504.html
Copyright © 2011-2022 走看看