• Python学习笔记--装饰器


    Python学习笔记--装饰器

    当你要提升自己颜值的时候该如何做? 可以整容,但是能不能在不修改本身器官下来提升颜值?
    答案就是装饰器

        def add(x,y):
            print("I am working now")
            return x+y
    
    • 你编写了一段程序,但是你觉得功能不够,例如你希望在运行add的时候,增加一段解释性的输出.就可以这样子.

        def deco(func):
            print("The value is ")
            return func
            print(deco(add(3,9)))
      
    • 输出是
      I am working now
      The value is
      12

    • 这样就做到了在没有改写代码的情况下增加了功能.可能你觉得这个例子有点简单,我们在看一个复杂点的.


    • 需求1:在执行add()方法的时候增加类型检查.

          def requires_int(decorated):
            def inner(*args,  **kwargs):
                kwargs_value=[i for i in kwargs.values()]
                for arg in list(args)+kwargs_value:
                    print(arg)
                    if not isinstance(arg,int):
                        raise TypeError('%s only accepts integers as arguments'%decorated.__name__)
                return decorated(*args,**kwargs)
            return inner
      
      
      
            def add(x,y):
              """ Return the sum of x and y"""
              return x+y
      
            add=requires_int(add)
            add('3',5)
      
            TypeError: add only accepts integers as arguments
      
    • 但是有人疑问,写的太麻烦了,不如直接在代码上加一个类型检查. 但是如果再增加一个需求呢?


    需求二:计算程序运行事件.

              def addTime(decorated):
                  def inner(x,y):
                      start=time.clock()
                      decorated(x,y)
                      end=time.clock()
                      addTime=(end-start)*1000
                      print("Time used",addTime)
                      return decorated(x,y)
                  return inner
                  add=addTime(add)
              Time used 0.03699999999999884     
    
    • 如果再有新需求,再写一个装饰器就可以了.是不是很方便?

    并且,两个装饰器还可以一起用.像这样

                add=addTime(add)
                add=requires_int(add)
                add(4,8)
    

    但是这样写感觉好麻烦,每次都要赋值一次,没关系,python为你专门准备了语法糖.其实可以这样写

              @addTime
              @requires_int
              def add(x,y):
                  """ Return the sum of x and y"""
                  time.sleep(0.7)
                  return x+y
    

    感觉有点眼熟,Django的login_required()不就是这样写的吗.不仅是这样,Flask的路由也是装饰器写的@route.

    需要注意的是,如果多个装饰器,运行顺序是从下到上.

    瞬间觉得装饰器好有用,不好好学习不行了.


    让我们再来学习一个实例. 需求3如果我们要写一个注册表装饰器.#每次运行一个函数,都会有记录这个函数#.

                registers=[]
                def register(decorated):
                    registers.append(decorated)
                    return decorated
    
                @register
                def foo():
                    return 3
    
                @register
                def bar():
                    return 5
    
                for i in registers:
                    print(i())
    

    最后输出3,5. 但是有点问题是,我觉得应该不同的函数的register应该分开.这应该怎么办呢

    答案是写一个装饰器类

              class Register(object):
                  def __init__(self):
                      self._functions=[]#定义一个列表来装被装饰的函数
    
                  def register(self,decorated):#装饰函数
                      self._functions.append(decorated)
                      return decorated
    
                  def run_all_function(self,  *args,  **kwargs):
                      return_values=[]
                      for func in self._functions:
                              return_values.append(func(*args,  **kwargs))
                      return return_values
    
    
                      
                      a=Register()
                      b=Register()
    
                      @a.register
                      def foo(x=5):
                          return x
    
                      @b.register
                      def bar(x=4):
                          return x
    
    
                      @a.register
                      @b.register
                      def baz(x=7):
                          return x
    
                      print(a.run_all_function())
                      print(b.run_all_function())
    
                      [5, 7]
                      [4, 7]
    

    这样就可以做到互相不影响,每一个register都是不同实例,数值不会混乱,是不是特别方便?

    让我们总结一下今天的学习.

                 装饰器可以在不修改代码下增加功能
                 装饰器可以叠加
                 装饰器可以写成一个类
  • 相关阅读:
    Python字典
    Python集合
    Hungray匈牙利算法
    异常捕获模块,throw, try, catch, finally
    《加德纳艺术通史》罗杰克-劳利
    《高效休息法》久贺谷亮
    梯度检验 Gradient check,bias correction, Exponentially Weighted Averages
    方差与偏差,bias vs variance
    大数定理,中心极限定理以及一些常见分布
    聚类-均值漂移
  • 原文地址:https://www.cnblogs.com/maxaimee/p/6526255.html
Copyright © 2020-2023  润新知