装饰器本质上是一个Python函数,它可以让其他函数在不雲要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
它经常用于有切面雲求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大畺与函数功能本身无关的雷同代码并继续重用。
概括的讲,装饰器的作用就是为已经存在的对象添加颉外的功能。
定义:
本质是函数,装饰器他函数,为器他函数添加附加功能。
原则:
不能修改被装饰函数的源代码
不能修改被装饰函数的调用方法
总结:
装饰器对被装饰的函数,是完全透明的,没有任何影响。
举个例子:
下面有一个函数,需要加一个功能,打印程序执行的时间
import time
def test1():
#等待1秒,表示代码逻辑部分,这里直接简写了
time.sleep(1)
print('in the test1')
这个函数已经上线很久了,如果更改源代码,是有风险的。
这个时候,用装饰器,就可以解决这个问题。
import time
def timmer(func):
def warpper(*args,**kwargs):
start_time = time.time()
func()
stop_time = time.time()
print('the func run time is %s' %(stop_time - start_time))
return warpper
@timmer
def test1():
time.sleep(1)
print('in the test1')
test1()
执行输出
in the test1
the func run time is 1.0007095336914062
首先需要写一个装饰器函数,在被装饰的函数名上一行,加@装饰器函数名,就可以了
实现装饰器知识储备:
1.函数即"变量"
2.高级函数
a.把一个函数名当作实参传给另外一个函数(不修改被装饰函数的源代码前提下,为其添加功能)
b.返回值中包含函数名(不修改函数的调用方式)
3.嵌套函数
高阶函数+嵌套函数 = 装饰器
def bar():
print('in the bar')
def test1(func):
print(func)
test1(bar)
执行输出
得到的结果是一个内存地址。
def bar():
print('in the bar')
def test1(func):
print(func)
func()
test1(bar)
执行输出
in the bar
func执行,得到一个内存地址,因为它是一个变量,函数即变量
func()执行,就是把内存地址的内容调取出来,得到in the bar
import time
def bar():
time.sleep(1)
print('in the bar')
def test1(func):
start_time = time.time()
#执行bar()函数
func()
stop_time = time.time()
print('the func run time is %s' % (stop_time - start_time))
test1(bar)
执行输出
in the bar
the func run time is 1.000032901763916
test1(bar)执行的时候,把bar函数传进去了
那么test1函数体内的func就等同于bar函数
所以程序执行,输出了上面2行的结果。
上面的代码,貌似实现了装饰器的功能。源代码bar,并没有修改啊,但是违背了第2个原则,修改了函数的调用方法。
默认bar函数调用时,直接bar()就可以了,现在变成了test1(bar)。
import time
def bar():
time.sleep(1)
print('in the bar')
def test2(func):
print(func)
return func
print(test2(bar))
执行输出
function bar at 0x0000017DFD6E3E18
function bar at 0x0000017DFD6E3E18
返回的结果是一个内存地址
把执行方式改一下
t = test2(bar)
print(t)
执行输出
function bar at 0x0000017DFD6E3E18
in the bar
貌似没什么卵用
再改一下
t = test2(bar)
t()
执行输出
function bar at 0x0000017DFD6E3E18
in the bar
t()相当于执行了bar函数,貌似没啥卵用
再改一下
bar = test2(bar)
bar()
执行输出
function bar at 0x0000017DFD6E3E18
in the bar
结果和上面是一样的,但是调用方式,发现和原函数调用是一模一样的。
下面打印一下bar的类型是变量还是函数
bar = test2(bar)
print(type(bar))
bar()
执行输出
可以看出,bar赋值之后,变成了函数,为什么呢?因为test2本身就是函数,所以它当然是函数了。
所以才可以执行bar()
但是bar()已经不是原来的bar函数了,而是被装饰过的函数。
因为原来的bar执行,只会输出 in the bar
函数嵌套:
定义:在一个函数中定义了另外一个函数
在一个函数体内,用def去声明一个新的函数,而不是去调用它。
下面是一个嵌套函数
def foo():
print('in the foo')
def bar():
print('in the bar')
bar()
foo()
执行输出
in the foo
in the bar