“深入浅出python中装饰器的原理。”
python版本.6
装饰器的概念:装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。而实际上,装饰器就是一个闭包,把一个函数当做参数然后返回一个替代版函数。
1.python的装饰器就是闭包函数的一种应用场景,在运用的时候我们遵循
开放封闭原则:对修改封闭,对拓展开放
2.什么是装饰器
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
.装饰器之前先来了解闭包
闭包的实现Python中的装饰器是通过闭包实现的,简单地讲,闭包就是引用了外部变量的内部函数,而闭包的实现正是利用了以上函数特性,下面我们来看看闭包是如何实现的:
defouter(x):definner():#内部函数returnx#跨域访问,引用了外部变量xreturninner#函数作为返回值closure=outer(外部变量)#函数作为变量赋给closureprint(closure())#执行闭包
在这个流程中,outer接收到外部变量,传给inner,作为它return的参数,最后outer返回inner函数,返回的inner函数作为变量传递给closure,最后执行closure这个函数对象,实际上是执行了inner这个函数,返回了外部变量,这样就实现了一个简单的闭包。上面这个闭包例子只用到了之前说的三个函数特性,函数作为参数这个特性好像并没有用上,下面做一下延伸,把outer的参数x用一个函数对象替代:
deffunc():returnfuncdefouter(x):definner():#函数嵌套returninner+x()#跨域访问,引用了外部变量xreturninner#函数作为返回值closure=outer(func)#函数func作为outer的参数;函数作为变量赋给closureprint(func())#执行原始函数print(closure())#执行闭包
closure实际上是outer(func),func作为参数传进outer,outer的子函数inner对func返回的结果进行了一番装饰,返回了一个装饰后的结果,最后outer返回inner,可以说inner就是装饰后的func,这就是一个函数被装饰的过程,重点在于执行outer(func)这个步骤。
4.函数特性
Python中的装饰器是通过利用了函数特性的闭包实现的,所以在说装饰器之前,我们需要先了解函数特性,以及闭包是怎么利用了函数特性。
1.函数作为变量传递defadd(x):returnx+1a=add2.函数作为参数传递
defadd(x):returnx+1defexcute(f):returnf()excute(add).函数作为返回值
defadd(x):returnx+1defget_add():returnadd4.函数嵌套及跨域访问
defouter():x=1definner():print(x)inner()outer()
5.装饰器的实现
在如上闭包的时候我们知道,在python中函数是一等公民,函数就是一个对象。这意味着函数:
1能在函数中定义一个函数。
2能作为参数传递。
能作为返回值。
defdecorator(func):defwrapper(*args,**kwargs):print(12)returnfunc(*args,**kwargs)returnwrapperdefsay_hello():print(同学你好)say_hello_super=decorator(say_hello)say_hello_super()输出:12同学你好
我们将一个函数say_hello作为参数传入函数decorator,返回一个wrapper函数并赋值到say_hello_super,此时执行say_hello_super相当于执行wrapper函数。当我们执行wrapper函数时会先打印12再执行先前传入的func参数也就是say_hello函数。
注意wrapper的*args与**kwargs参数,这是必须的,*args表示所有的位置参数,**kwargs表示所有的关键字参数。之后再将其传到func函数中,这样保证了能完全传递所有参数。在这里,decorator这个函数就是一个装饰器,功能是在执行被装饰的函数之前打印12。在python中的语法糖可以代替say_hello_super=decorator(say_hello)这一步的操作=
decorator。defdecorator(func):defwrapper(*args,**kwargs):print(12)returnfunc(*args,**kwargs)returnwrapper
decoratordefsay_hello():print(同学你好)say_hello()5.装饰器语法糖
装饰器的语法糖就是
符号。它放在一个函数开始定义的地方,它就像一顶帽子一样戴在这个函数的头上。和这个函数绑定在一起。在我们调用这个函数的时候,第一件事并不是执行这个函数,而是将这个函数做为参数传入它头顶上这顶帽子,这顶帽子我们称之为装饰函数或装饰器。#装饰器语法糖#在被装饰器对象上方单独一行写:
装饰器的名称解释器一旦执行到装饰器的名字就会执行原函数名=装饰器的名字(函数)#修订之后的装饰器importtimedeftimmer(func):#func=最原始那个index的内存地址defwrapper(*args,**kwargs):start=time.time()res=func(*args,**kwargs)stop=time.time()print(runtimeis%s%(stop-start))returnresreturnwrapper#index=timmer(最原始那个index的内存地址)#index=wrapper的内存地址timmerdefindex():time.sleep(1)print(wel