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)
点赞