zoukankan      html  css  js  c++  java
  • Python-装饰器的进阶 小知识点

    . 通⽤装饰器的回顾
      开闭原则: 对增加功能开放. 对修改代码封闭
      装饰器的作⽤: 在不改变原有代码的基础上给⼀个函数增加功能
      通⽤装饰器的写法:

    def wrapper(fn):
        def inner(*args, **kwargs):
            '''在⽬标函数之前做的事情'''
            ret = fn(*args, **kwargs)
            '''在⽬标函数执⾏之后做的事情'''
            return ret
        return inner
    @wrapper
    def target_func():
        '''⽬标函数体'''
    target_func()
    

      执⾏过程:
    1. 程序从上向下, 当执⾏到@wrapper的时候. 把函数作为参数传递给wrapper函数. 得到
      inner函数. 重新赋值给target_func
    2. 当执⾏到target_func的时候. 我们实际上执⾏的是inner函数. inner函数会先执⾏⽬标
      函数之前的代码. 然后再执⾏你的⽬标函数. 执⾏完⽬标函数最后执⾏的是⽬标函数
      之后的代码

    . 函数的有⽤信息
      1. 如何给函数添加注释

    def chi(food, drink):
        """
        这⾥是函数的注释, 先写⼀下当前这个函数是⼲什么的, ⽐如我这个函数就是⼀个吃
        :param :param food: 参数food是什么意思:param :param drink: 参数drink是什么意思
        :return :return: 返回的是什么东东
        """
        print(food, drink)
        return "very good
    

      2. 如何获取到函数的相关信息

    def chi(food, drink):
      """
      这⾥是函数的注释, 先写⼀下当前这个函数是⼲什么的, ⽐如我这个函数就是⼀个吃
      :param :param food: 参数food是什么意思
      :param :param drink: 参数drink是什么意思
      :return :return: 返回的是什么东东
      """
      print(food, drink)
      """
      这个可以获取到么
      """
      print(chi.__doc__) # 获取函数的⽂档注释
      print(chi.__name__) # 获取到函数名称
      return "very good"
    chi("吃嘛嘛⾹", "我不想吃")
    print(chi.__doc__)
    print(chi.__name__)
    

      函数名.__name__可以查看函数的名字
      函数名.__doc__ 可以查看函数的⽂档注释

    接下来. 我们来看⼀看被装饰器装饰之后的函数名 :

    # 装饰器: 对传递进来的函数进⾏包装. 可以在⽬标函数之前和之后添加任意的功能.
    def wrapper(func):
        def inner(*args, **kwargs):
            '''在执⾏⽬标函数之前要执⾏的内容'''
            ret = func(*args, **kwargs)
            '''在执⾏⽬标函数之后要执⾏的内容'''
            return ret
        return inner
    # @wrapper 相当于 target_func = wrapper(target_func) 语法糖
    @wrapper
    def target_func():
    print("我是⽬标函数")# 调⽤⽬标函数
    target_func()
    print(target_func.__name__) # inner
    结果:
    inner
    

      我们虽然访问的是target_func函数. 但是实际上执⾏的是inner函数. 这样就会给下游的程
    序员带来困惑. 之前不是⼀直执⾏的是target_func. 为什么突然换成了inner. inner是个什
    么⿁?? 为了不让下游程序员有这样的困惑. 我们需要把函数名修改⼀下. 具体修改⽅案

    from functools import wraps # 引⼊函数模块
    
    # 装饰器: 对传递进来的函数进⾏包装. 可以在⽬标函数之前和之后添加任意的功能.
    def wrapper(func):
        @wraps(func) # 使⽤函数原来的名字
        def inner(*args, **kwargs):
            '''在执⾏⽬标函数之前要执⾏的内容'''
            ret = func(*args, **kwargs)
            '''在执⾏⽬标函数之后要执⾏的内容'''
            return ret
        return inner
    # @wrapper 相当于 target_func = wrapper(target_func) 语法糖
    @wrapper
    def target_func():
        print("我是⽬标函数")
    # 调⽤⽬标函数
    target_func()
    print(target_func.__name__) # 不再是inner. ⽽是target_func了
    @wrapper
    def new_target_func():
        print("我是另⼀个⽬标函数")
    new_target_func()
    print(new_target_func.__name__)
    

      PS: *args**kwargs什么时候打散, 什么时候聚合
      1. 接收参数的时候是聚合, 参数声明
      2. 传递参数的时候是打散, 给函数传递实参

    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs): # 这⾥是聚合
            '''在执⾏⽬标函数之前要执⾏的内容'''
            ret = func(*args, **kwargs) # 这⾥是打散, 这⾥的作⽤. 其实就是为了保证我可以装饰所有函数⽽准备的
            '''在执⾏⽬标函数之后要执⾏的内容'''
            return ret
        return inner
    

      . 装饰器传参
    现在来这样⼀个场景. 还是昨天的约

    from functools import wraps
    def wrapper(fn):
        @wraps(fn)
        def inner(*args, **kwargs):
            print("问问⾦⽼板啊, ⾏情怎么样.")
            ret = fn(*args, **kwargs)
            print("⺾, ⾦⽼板骗我")
            return ret
        return inner
    @wrapper
    def yue():
        print("约⼀次⼜不会死")
    yue()
    

      那么现在如果查的很严. 怎么办呢? 打电话问⾦老板严不严. 那如果整体⻛声都不是那么
    紧呢. 是不是就不需要问⾦老板了. 所以. 我们需要⼀个开关来控制是否要询问⾦老板. 这时
    我们就需要给装饰器传递⼀个参数. 来通知装饰器要⽤怎么样的⽅式来装饰你的⽬标函数

    from functools import wraps
    def wrapper_out(flag):
        def wrapper(fn):
            @wraps(fn)
            def inner(*args, **kwargs):
                if flag == True: # 查的严啊. 先问问吧
                    print("问问⾦⽼板啊, ⾏情怎么样.")
                    ret = fn(*args, **kwargs)
                    print("⺾, ⾦⽼板骗我")
                    return ret
                else: # 查的不严. 你慌什么
     	       ret = fn(*args, **kwargs)
                    return ret
            return inner
        return wrapper
    @wrapper_out(False) # 传递True和False来控制装饰器内部的运⾏效果
    def yue():
    print("约⼀次⼜不会死")
    yue()
    

      注意: 咱们之前的写法是@wrapper 其中wrapper是⼀个函数. 那么也就是说. 如果我能让
    wrapper这⾥换成个函数就⾏了. wrapper(True)返回的结果是wrapper也是⼀个函数啊. 刚刚
    好和前⾯的@组合成⼀个@wrapper. 依然还是原来那个装饰器. 只不过这⾥套了3. 但你要
    能看懂. 其实还是原来那个装饰器@wrappe
    r
    执⾏步骤: 先执⾏wrapper(True) 然后再@返回值. 返回值恰好是wrapper. 结果就是
    @wrapper

     

    . 多个装饰器装饰同⼀个函数
      先读⼀下这样⼀个代码.

    def wrapper1(fn):
      def inner(*args, **kwargs):
        print("111")
        ret = fn(*args, **kwargs)
        print("222")
        return ret
      return inner
    def wrapper2(fn):   def inner(*args, **kwargs):     print("333")     ret = fn(*args, **kwargs)     print("444")     return ret   return inner @wrapper2 @wrapper1 def eat(): print("我想吃⽔果") eat() 结果: 333 111 我想吃⽔果 222 444

      执⾏顺序: ⾸先@wrapper1装饰起来. 然后获取到⼀个新函数是wrapper1中的inner. 然后执
    @wrapper2.这个时候. wrapper2装饰的就是wrapper1中的inner. 所以. 执⾏顺序就像:
    第⼆层装饰器前(第⼀层装饰器前(⽬标)第⼀层装饰器后)第⼆层装饰器后. 程序从左到右执⾏
    起来. 就是我们看到的结果

     

    小知识点:
    1. decode : 解码 : 将bytes类型转成字符串
    # s = "提前祝大家生日快乐"
    # bys = s.encode("UTF-8") # 编码
    # print(bys)
    # s1 = bys.decode("UTF-8")    # 解码
    # print(s1)
    
    # 把utf-8 转换成GBK的bytes
    # bys = b'xe6x8fx90'
    # s = bys.decode("utf-8")
    # gbk_bys = s.encode("gbk")
    # print(gbk_bys)
    

      

    1. enumerate() : 枚举 : 可以直接获取到索引和元素
    2. lst = ["彭于晏", "詹姆斯", "奥特曼", "唐僧"]
      
      # for e in lst:
      #     print(e)
      # for i in range(0, len(lst)):
      #     print(i)
      
      # for index, element in enumerate(lst): # enumerate 可以直接获取到索引和元素
      #     print(index, element)
      
      # for e in enumerate(lst):
      #     print(e)
      

        

     



      

     

  • 相关阅读:
    关于SQL优化(转载,格式有调整)
    开篇(我想有个家,安稳的家)
    常见兼容问题
    BFC概念及应用
    浏览器私有前缀及内核
    css3新增属性
    宽高自适应
    css布局
    css3选择器
    常用标签
  • 原文地址:https://www.cnblogs.com/liuye1990/p/9187681.html
Copyright © 2011-2022 走看看