• python装饰器


     

    参考:

    https://www.runoob.com/w3cnote/python-func-decorators.html

    https://www.jb51.net/article/240440.htm

    用途:定义一个函数,来修饰之前老的代码,以便在不修改原代码的情况下增加新功能

    关键原理:把函数作为参数,函数后面不加()就可以随意传递,加了()函数就会执行

    一. 第一个装饰器例子

    1.基本功能实现
    def deco(func):
      def inner():
        print("something before hi")
        func()
        print("something after hi")
      return inner
    ​
    def hi():
      print("hi")
    ​
    hi=deco(hi)
    hi()
    这正是 python 中装饰器做的事情!它们封装一个函数,并且用这样或者那样的方式来修改它的行为
    2.现在用符号@来修改上面代码
    def deco(func):
      def inner():
        print("something before hi")
        func()
        print("something after hi")
      return inner
    ​
    @deco
    def hi():
      print("hi")
    ​
    hi()
    print(hi.__name__) //输出为inner

    @deco其实就相当于hi=deco(hi)

    不过现在最后一个行输出为inner, 我们想把它输出为hi,应该怎么做呢?

    幸运的是Python提供给我们一个简单的函数来解决这个问题,那就是functools.wraps

    3. functools.wraps改写
    from functools import wraps
    ​
    def deco(func):
      @wraps(func)
      def inner():
        print("something before hi")
        func()
        print("something after hi")
      return inner
    ​
    @deco
    def hi():
      print("hi")
    ​
    hi()
    print(hi.__name__) //输出为hi

    @wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

     

    二. 带参数的装饰器

    from functools import wraps
    import time
    ​
    def delay_deco(delay=0):
      def deco(func):
        @wraps(func)
        def inner():
          print("something before hi")
          time1 = time.time()
          time.sleep(delay)
          time2 = time.time()
          func()
          print("something after hi")
          print("耗时:{:.8f}".format(time2-time1))
        return inner
      return deco
    ​
    @delay_deco(2.0)
    def hi():
      print("hi")
    ​
    hi()
    print(hi.__name__) 

    其实就是在原先的基础上,再加一层嵌套。上面代码实现延迟2秒执行,参数就是延迟的时间

     

    三. 类装饰器

    装饰器本身既可以是函数也可以是类,装饰的对象同样可以是函数也可以是类。

    1. 最简单的例子
    class Deco:
      def __init__(self, func):
        self._func = func
    ​
      def __call__(self, *args, **kwargs): #定义__call__函数,让类实例成为可调用对象
        print("类装饰器")
        return self._func(*args, **kwargs)
    ​
    @Deco
    def test():
      print("被装饰函数")
    ​
    test()
    例子2:根据例子1,稍微复杂点,被装饰的函数中添加参数
    import time
    ​
    class Deco:
      def __init__(self, func):
        self.func = func
    ​
      def __call__(self, *args, **kwargs):
        start = time.time()
        ret = self.func(*args, **kwargs)
        print(f'Time: {time.time()-start}')
        return ret
    ​
    @Deco
    def add(a,b):
      time.sleep(1)
      return a+b
    ​
    print(add(3,4))
    这个装饰器,相当于把一个装饰器变成了一个Deco类的对象,然后add被传入进了init中,保存为self.func
    在后面调用add(3,4)的时候,实际上相当于调用了call这个函数,做了一个对象的调用,后面参数3和4就被传入到了call里面,然后依顺序运行了代码。
    例子3:带参数的类装饰器
    import time
    ​
    class Deco:
      def __init__(self, prefix):
        self.prefix = prefix
        
      def __call__(self, func):
        def inner(*args, **kwargs):
          start = time.time()
          ret = func(*args, **kwargs)
          print(f'{self.prefix}: {time.time()-start}')
          return ret
        return inner
    ​
    @Deco(prefix='current_time')
    def add(a,b):
      time.sleep(1)
      return a+b
    ​
    print(add(3,4))

    我们把参数写入init函数中,相当于先实例化了一个Deco对象,call函数内做一个嵌套,类似于函数装饰器

  • 相关阅读:
    7/31 CSU-ACM2018暑期训练7-贪心
    树状数组
    洛谷 P2947 [USACO09MAR]向右看齐Look Up【单调栈】
    如何求先序排列和后序排列——hihocoder1049+洛谷1030+HDU1710+POJ2255+UVA548【二叉树递归搜索】
    HDU 1611 敌兵布阵【线段树模板】
    Poj 2112 Optimal Milking (多重匹配+传递闭包+二分)
    Hdu 5361 In Touch (dijkatrs+优先队列)
    Codeforces Round #Pi (Div. 2)
    Hdu 5358 First One (尺取法+枚举)
    Poj 3189 Steady Cow Assignment (多重匹配)
  • 原文地址:https://www.cnblogs.com/regit/p/16802360.html
Copyright © 2020-2023  润新知