zoukankan      html  css  js  c++  java
  • python-装饰器简述

    装饰器是什么

    用来修饰别的函数的函数就可以称之为装饰器
    这种函数的参数一般就是另外一个函数
    也就是说,调用这种函数,需要给这种函数传参,且参数是函数

    @语法糖

    @语法糖一般用来表示装饰器函数
    不用@也可以达到装饰函数的目的,下面会有演示

    函数嵌套

    在一个函数中定义另外一个函数

    def f1(arg="aaa"):
          def f2():
    	       return "hello"
    	  def f3():
    	      return "hi"
    	  def f4():
    	     return "haha"
          
    	 print f2()
    	 print f3()
    	 print f4()
    

    这个f1函数有默认参数,所以可以不传参执行
    执行f1()调用之后
    执行结果如下:
    hello
    hi
    haha

    在函数里返回函数
    def hi(arg="aaa"):
        def greet():
            return "bbb"
    
        def welcome():
            return "ccc"
    
        if arg == "aaa":
            return greet
        else:
            return welcome
    
    a = hi()
    print(a)
    print (a())
    

    这里同样使用了默认参数,则a = hi() 会命中 if arg == "aaa"这个逻辑
    返回greet,注意在这里,greet是函数,不是字符串,如果是返回字符串,则要返回的是 return "greet"这种
    上面这段代码执行的结果是
    <function greet at 0x7f75f7a0e1b8>
    bbb

    为什么是这样的执行结果呢?第一个地方 print(a),打印的是a = hi()的结果
    我们可以看到,hi()的返回结果都是在return一个函数,要么是greet函数,要么是welcome函数
    函数就是对应一个地址,所以第一处打印的是这个函数的地址
    第二处做了a的调用,即a(),则打印返回的函数即greet函数执行的结果,即bbb

    将函数作为参数传给另外一个函数
    def hi():
        return "hi"
    
    def hello(func):
        print("before func()")
        print(func())
    
    hello(hi)
    

    执行结果是
    before func()
    hi
    这里把hi这个函数作为参数传给hello函数
    hello函数先打印一句自身的输出before func()
    再执行这个被传入的函数
    我们可以看到,通过装饰器,我们可以在一个函数被调用前干一些需要的事情

    不用@实现装饰器
    def hi(a_func):
    
        def hello():
            print("I am doing some boring work before executing a_func()")
    
            a_func()
    
            print("I am doing some boring work after executing a_func()")
        return hello
    
    def haha():
        print("I am the function which needs some decoration ")
    
    haha = hi(haha)
    print haha()
    

    运行结果:

    I am doing some boring work before executing a_func()
    I am the function which needs some decoration
    I am doing some boring work after executing a_func()
    None
    这个就是装饰器,起到了用hi函数装饰了haha函数的功能

    那么怎么用@语法糖实现呢
    def hi(a_func):
    
        def hello():
            print("I am doing some boring work before executing a_func()")
    
            a_func()
    
            print("I am doing some boring work after executing a_func()")
        return hello
    
    @hi
    def haha():
        print("I am the function which needs some decoration ")
    
    haha()
    

    可以看到,装饰器就是用希望装饰别的函数的函数,比如 ,希望用A装饰B
    就在定义B函数的上一行,写上 @A

    def A():
         pass
    	 
    	 
    @A	 
    def B():
        pass
    

    总结:理解就是装饰器其实就是这样一种函数:带参数的,且参数是另外一个函数的函数
    使用装饰器的目的一般是为了在运行时改变函数的一些属性/行为,就可以给这个函数加上装饰器,让装饰器去在这个函数被调用前后,干一些你想做的事情

    wraps干什么的?

    我们修改下上面的代码,多记录一点东西

    def hi(a_func):
    
        def hello():
            print("I am doing some boring work before executing a_func()")
    
            a_func()
    
            print("I am doing some boring work after executing a_func()")
        return hello
    
    @hi
    def haha():
        print("I am the function which needs some decoration ")
    
    haha()
    print(haha.__name__)
    

    我们的意图是打印haha这个函数的函数名,但实际上打印的是hello
    为什么?
    因为haha这个函数使用装饰器之后,haha的行为部分被装饰器函数改变了
    可以看到,用hi函数装饰了haha之后,返回的是hello函数,那么当我们需要拿到被装饰函数的函数名,还有其他属性的时候怎么做呢?
    使用functools.wraps方法

    from functools import wraps
     def hi(a_func):
       @wraps(a_func)
        def hello():
            print("I am doing some boring work before executing a_func()")
    
            a_func()
    
            print("I am doing some boring work after executing a_func()")
        return hello
    
    @hi
    def haha():
        print("I am the function which needs some decoration ")
    
    haha()
    print(haha.__name__)
    

    执行结果如下:

    I am doing some boring work before executing a_func()
    I am the function which needs some decoration
    I am doing some boring work after executing a_func()
    haha
    正是我们想要的结果
    @wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

    举一个记录日志的例子
    from functools import wraps
    
    def logit(func):
        @wraps(func)
        def with_logging(*args, **kwargs):
            print(func.__name__ + " was called")
            return func(*args, **kwargs)
        return with_logging
    
    @logit
    def addition_func(x):
       """Do some math."""
       return x + x
    
    
    result = addition_func(4)
    # Output: addition_func was called   
    
  • 相关阅读:
    Python画图代码
    关于meshgrid和numpy.c_以及numpy.r_
    Reshape以及向量机分类学习和等高线绘制代码
    Python中的数组和list
    关于透视图和等高线
    Iris花逻辑回归与实现
    Crowd安装和破解
    Confluence搭建
    基于搜狗微信搜索获取公众号文章的阅读量及点赞量
    PHP中使用cURL实现Get和Post请求的方法
  • 原文地址:https://www.cnblogs.com/haozike/p/python_decorator_summary.html
Copyright © 2011-2022 走看看