一文轻松理解python装饰器

一、python中,装饰器是什么(decorator)

装饰器是python中的一个很重要的概念,它的作用,顾名思义是装饰一个东西,既然是装饰,也暗示着,不会去改变被装饰的东西。
学过初中数学的都知道函数。比如一个简单的函数 y=Ax+b ,也可以写成 y= f(x)=Ax+b,装饰器其实就和数学中的函数一样,传入一个 变量x, 通过f(x)这个函数,把结果变成y, 并且x本身是不变的。而我们使用装饰器,也是为了在不改变原函数的内部结构的前提下,对原函数进行功能的扩展和修改(这个同样是为了符合开放封闭准则)。
总结:装饰器的基本过程是python函数接受一个函数作为参数 并返回一个函数

二、装饰器可以实现关键因素

上面总结的:装饰器的基本过程是python函数接受一个函数作为参数 并返回一个函数,对这句话,我们推敲一下关键点。

关键点一:python的参数是不是可以是函数,并且返回值也是一个函数,为什么可以这样
关键点二:是通过什么方式去扩展这个函数的功能

对于关键点一:我们常说,python中一切皆对象,函数也是对象,所以,函数也可以作为另一个函数的参数被传入 ,同理也可以返回一个函数。这个更详细一点的可以搜索 python一切皆对象的原因,这个不多阐述。

对于关键点二:实现这个扩展的功能是依靠一个叫 闭包的方式实现的,这个可以自行学一下,也可以参考下面程序先这样理解,闭包是一个函数A里嵌套了一个函数B,函数A最终返回函数B。这样的话,当我们调用函数A(),实际就是返回了一个函数B,如下

def A(fun):                                    
    def B():                                   
        fun()          
    return B                                    
result=A(fun)#   这个值返回的是函数 B             
resutlt()   #   这个就等价于B()                            

上面的 B函数内部是可以调用传入的参数 fun。 原本在函数A调用过后(执行result=A(fun)这个一步后 ),因为函数A里面参数 fun是个局部变量,会被销毁,但是通过嵌套一个函数B,B函数中调用fun, 又返回B的函数名 这个操作,就可以保存这个变量在函数B中,所以我们可以通过调用B继续调用到fun,这个就是闭包的作用。

在B函数当中,我们可以调用传入的参数fun。达到扩展和改变这个参数的目的,一般参数是普通变量我们把这个叫闭包,但是当这个参数是函数的时候,就形成了装饰器的概念 .

def A(fun):
    def B():
        print("---------加入装饰内容1--------------")
        fun()
        print("---------加入装饰内容2--------------")

    return B

三、python装饰器的格式 是什么样

python 中我们是用@函数名 来表示装饰器。放在哪个函数上面,就是装饰哪个函数,下面的就是表示装饰器 A, 装饰函数demo。
而这个装饰的结果也等价于 A(demo),也就是把函数demo,当成参数,传入函数A()里,返回一个新的函数,新的函数名也叫demo 公式表达就是demo= A(demo)

def A(fun):
    def B():
        print("---------加入装饰内容1--------------")
        fun()
        print("---------加入装饰内容2--------------")

    return B

#这个装饰就于demo= A(demo)
@A
def demo():
    print("hello world")


demo()

四、python实现简单的装饰器

4.1实现无参数的装饰器
def A(fun):                  
    def B():                  
        print("---------加入装饰内容1--------------")                  
        fun()                  
        print("---------加入装饰内容2--------------")                  

    return B                  

#这个装饰就于demo= A(demo)                  
@A
def demo():                  
    print("hello world")                  


demo()                  

在这里插入图片描述
这样每次调用demo函数可以加上打印,而不改变demo本身,这些打印的地方,完全可以替换成我们需要的前置操作和后置操作。

4.1实现有参数的装饰器
def A(fun):
    def B(x, y):
        print("---------加入装饰内容1--------------")
        fun(x, y)
        print("---------加入装饰内容2--------------")

    return B


# 这个装饰就于demo= A(demo)
@A
def demo(x, y):
    print('x+y=', x + y)


demo(1,2)

有参数的装饰器有点不同,我们要明确,demo有两个参数,我们用A去装饰这个demo的时候,等价于 demo= A(demo),所以这个A只能传入一个参数,就是demo这个函数的名字。函数被装饰过后,就是函数B了,所以直接拿出函数B出来看。

    def B():    
        print("---------加入装饰内容1--------------")    
        fun(x, y)    
        print("---------加入装饰内容2--------------")    

因为fun函数需要两个参数,所以函数 B中需要传入两个参数变量即

    def B(x,y):      #不同点在于B要接受传入的参数个数
        print("---------加入装饰内容1--------------")            
        fun(x, y)           
        print("---------加入装饰内容2--------------")            

最终就是开始展示的代码。

def A(fun):
    def B(x, y):
        print("---------加入装饰内容1--------------")
        fun(x, y)
        print("---------加入装饰内容2--------------")

    return B


# 这个装饰就于demo= A(demo)
@A
def demo(x, y):
    print('x+y=', x + y)


demo(1,2)
4.2实现有参数的装饰器进阶版,参数不定长

之前我们说的是参数有限,如果参数是不定长的参数呢,那么效果就是下面的,通过解包操作来看解析出个数

    def B(*args, **kwargs):  #不同点在于B要接受传入的参数个数
        print("---------加入装饰内容1--------------")            
        fun(*args, **kwargs)           
        print("---------加入装饰内容2--------------")            

最终于代码是

def A(fun):
    def B(*args, **kwargs):
        print("---------加入装饰内容1--------------")
        fun(*args)
        print("---------加入装饰内容2--------------")

    return B


# 这个装饰就于demo= A(demo)
@A
def demo(x, y):
    print('x+y=', x + y)


demo(1,2)

4.2实现有 return的关键字的函数的装饰
def A(fun):
    def B():
        print("---------加入装饰内容1--------------")
        fun()
        print("---------加入装饰内容2--------------")

    return B


# 这个装饰就等于demo= A(demo)
@A
def demo():
    return 'hello world'


print(demo())  

在这里插入图片描述

当被装饰的函数里有通过return 返回一个值的时候,这个返回的值给到的是当前的函数,比如上面的demo函数,通过return返回,返回值给到的是demo这个函数本身, 在被装饰器A装饰的时候,fun 函数的 return的值没有返回给B。 返回值给到的是fun.
所以要把fun(), 加个return,返回给函数B 这样才能打印出来

def A(fun):   
    def B():   
        print("---------加入装饰内容1--------------")   
        result = (fun())   
        return result #和之前的区别在这里 ,加了一个return函数。 
        print("---------加入装饰内容2--------------")   

    return B   


# 这个装饰就于demo= A(demo)   
@A
def demo():   
    return 'hello world'   


print(demo())   

在这里插入图片描述

4.3 多个装饰器对同一个函数装饰

当多个装饰器对一个函数进行装饰的时候,如下面所示

def A(fun): 
    def B(): 
        print("---------加入装饰内容1--------------") 
        fun() 
        print("---------加入装饰内容2--------------") 

    return B 


def X(fun): 
    def Y(): 
        print("---------加入装饰内容3--------------") 
        fun() 
        print("---------加入装饰内容4--------------") 

    return Y 


# 这个装饰就于demo= X( A(demo)) 
@X
@A
def demo(): 
    print('hello world') 


demo()     

当被多个装饰器装饰的时候,比如上面的demo,就等价于 demo= X( A(demo)) 和数学中函数一样,我们可以从内到外一步步解析或者从外到内一步步解析。如果从外到内来说,先把A(demo) 当成一个整体,就可以看出打印的顺序时先打印装饰内容3,再运行fun,这个fun就是A(demo),再打印装饰内容4.而这个fun 里,先打印装饰内容1,再运行这个函数的fun(),再打印装饰内容2.

在这里插入图片描述
在这里插入图片描述

  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值