zoukankan      html  css  js  c++  java
  • python三器——装饰器/迭代器/生成器

    一、装饰器

    1.1 目的

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

    1.2 应用场景

    • 想要为函数扩展功能时,可以选择用装饰器

    1.3 基本装饰器

    1. 基本格式:

      def func(arg):
          def inner():
              v = arg()
              return v 
          return inner 
      
      # 重点:
      # 第一步:执行func函数并将下面的函数参数传递,相当于:func(index)
      # 第二步:将func的返回值重新赋值给下面的函数名。 index = func(index)
      @func 
      def index():
          print(123)
          return 666
      
      print(index)
      
    2. 总结

      • 编写格式:
      def 外层函数(参数):
          def 内层函数(*args,**kwargs)
          	return 参数(*args,**kwargs)
          return 内层函数
      
      • 应用格式:
      @外层函数
      def index():             #要装饰的函数
          pass
      
      index()
      
      # 装饰器的编写
      def x(func):
          def y():
              # 前
              ret = func()
              # 后
              return ret 
         	return y 
      
      # 装饰器的应用
      @x
      def index():
          return 10
      
      # 执行函数,自动触发装饰器了
      v = index()
      print(v)
      
    3. 示例:

      def func(arg):
          def inner():
              print('before')
              v = arg()
              print('after')
              return v 
          return inner 
      
      def index():
          print('123')
          return '666'
      
      # 示例一
      v1 = index() # 执行index函数,打印123并返回666赋值给v1.
      
      # 示例二
      v2 = func(index) # v2是inner函数,arg=index函数
      index = 666 
      v3 = v2()
      
      # 示例三
      v4 = func(index)
      index = v4  # index ==> inner 
      index()
      
      # 示例四
      index = func(index)
      index()
      

    1.4 带参数的装饰器

    1. 应用场景:flask框架 / django缓存 / 写装饰器实现被装饰的函数要执行N次

      # 第一步:执行 ret = xxx(index)
      # 第二步:将返回值赋值给 index = ret 
      @xxx
      def index():
          pass
      
      # 第一步:执行 v1 = uuu(9)
      # 第二步:ret = v1(index)
      # 第三步:index = ret 
      @uuu(9)
      def index():
          pass
      
    2. 区别:

      # 普通装饰器
      def wrapper(func):
          def inner(*args,**kwargs):
              data = func(*args,**kwargs) # 执行原函数并获取返回值
              return data
          return inner 
      
      @wrapper
      def index():
          pass
      
      # 带参数装饰器 
      def x(counter):
          def wrapper(func):
              def inner(*args,**kwargs):
                  data = func(*args,**kwargs) # 执行原函数并获取返回值
                  return data
              return inner 
      	return wrapper 
      
      @x(9)
      def index():
          pass
      
    3. 练习题

      # 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,把每次结果添加到列表中,最终返回列表。
      def xxx(counter):
          def wrapper(func):
              def inner(*args,**kwargs):
                  v = []
                  for i in range(counter):
                      data = func(*args,**kwargs) # 执行原函数并获取返回值
                      v.append(data)
                  return v
              return inner
          return wrapper
      
      @xxx(5)
      def index():
          return 8
      v = index()
      print(v)
      

    二、 迭代器

    2.1 基本知识

    1. 用途:对 某种对象(str/list/tuple/dict/set类创建的对象-可迭代对象)中的元素进行逐一获取

    2. 表象:具有__next__方法且每次调用都获取可迭代对象中的元素(从前到后一个一个获取)

    3. 示例:

      • 列表转换成迭代器:
        • v1 = iter([11,22,33,44])
        • v1 = [11,22,33,44].__iter__()
      • 迭代器想要获取每个值:反复调用 val = v1.__next__()
      v1 = [11,22,33,44]
      
      # 列表转换成迭代器
      v2 = iter(v1)
      
      # 迭代器获取每个值
      result1 = v2.__next__()
      print(result1)
      result2 = v2.__next__()
      print(result2)
      result3 = v2.__next__()
      print(result3)
      result4 = v2.__next__()
      print(result4)
      
      result5 = v2.__next__()
      print(result5)    # 报错:Stoplteration    表示已经迭代结束
      
    4. for循环:运用了迭代器

      v1 = [11,22,33,44]
      
      # 1.内部会将v1转换成迭代器
      # 2.内部反复执行 迭代器.__next__()
      # 3.取完不报错
      for item in v1:
          print(item)
      

    2.2 可迭代对象

    1. 表象:可以被for循环的对象就可以称为是可迭代对象

    2. 如何让一个对象变成可迭代对象?

      • 在类中实现__iter__方法且返回一个迭代器(生成器)
      # 示例一:
      class Foo:
          def __iter__(self):
              return iter([1,2,3,4])
      
      obj = Foo()
      
      # 示例二:
      class Foo:
          def __iter__(self):
              yield 1
              yield 2
              yield 3
      
      obj = Foo()
      
    3. 注意:只要能被for循环,就是去看他内部的__iter__方法

    三、 生成器

    3.1 基本知识

    1. 可以理解为:函数的变异、特殊的迭代器、特殊的可迭代对象

    2. 生成器的作用:

      • 生成数据
      • 迭代
    3. 示例:

      # 生成器函数(内部是否包含yield)
      def func():
          print('F1')
          yield 1
          print('F2')
          yield 2
          print('F3')
          yield 100
          print('F4')
      # 函数内部代码不会执行,返回一个 生成器对象 。
      v1 = func()
      # 生成器是可以被for循环,一旦开始循环那么函数内部代码就会开始执行。
      for item in v1:
          print(item)
      

    3.2 关键字

    1. yield

      • 用途:判断函数是否是生成器函数
    2. yield from

      • 用途:从当前生成器函数跳到其他生成器函数中,执行结束后再回原函数继续执行下面代码
      def base():
          yield 88
          yield 99
      
      def func():
          yield 1
          yield 2
          yield from base()   # 跳到base函数
          yield 3
      
      result = func()
      for item in result:
          print(item)       # 1   2   88   99   3
      

    3.3 总结

    1. 重点:

      • 函数中如果存在yield,那么该函数就是一个生成器函数
      • 调用生成器函数会返回一个生成器
      • 生成器只有被for循环时,生成器函数内部的代码才会执行,每次循环都会获取yield返回的值
    2. 建议:

      • 生成器函数中一般不要有return

      • 如果需要终止生成器函数中的循环,可以用return

        def func():
            count = 1
            while True:
                yield count
                count += 1
                if count == 100:
                    return
        val = func()
        for item in val:
            print(item)
        
    3. 生成器示例:读取大文件内容

      def func():
          #  分批去读取文件中的内容,将文件的内容返回给调用者。
          cursor = 0
          while True:
              f = open('db', 'r', encoding='utf-8')    # 通过网络连接上redis
              # 代指  redis[0:10]
              f.seek(cursor)
              data_list =[]
              for i in range(10):
                  line = f.readline()
                  if not line:
                      return
                  data_list.append(line)
              cursor = f.tell()
              f.close()  # 关闭与redis的连接
      
              for row in data_list:
                  yield row
      
      for item in func():
          print(item)
      
    勤勤恳恳更博,点点滴滴记录
  • 相关阅读:
    测试随笔
    代码规范与计划
    WeChair项目Alpha冲刺(8/10)
    WeChair项目Alpha冲刺(7/10)
    WeChair项目Alpha冲刺(6/10)
    WeChair项目Alpha冲刺(5/10)
    WeChair项目Alpha冲刺(4/10)
    WeChair项目Alpha冲刺(3/10)
    WeChair项目Alpha冲刺(2/10)
    代码规范
  • 原文地址:https://www.cnblogs.com/zengyi1995/p/10676822.html
Copyright © 2011-2022 走看看