您的位置:首页 > 编程语言 > Python开发

Python进阶(四):浅析装饰器(decorator)@

2017-10-17 21:00 323 查看
之前在看代码的时候看见有些代码会在函数前面用一个@+函数名修饰,开始有点困惑的。遂查找各种资料,才知道这是python的一种语法糖。虽然理解起来有点困难,可是理解过后就会佩服python的简洁性。

装饰器@

一.介绍

函数就是我们的衣服,单个函数就比如一件短袖衬衫。编程就是不断的调用不同的函数,就比我们身上穿不同的衣服。当天气变凉的时候我们就必须加外套了,相同的我们需要对某个函数进行某种操作(并且并不想改变这个函数的内部结构)的时候,装饰器就派上了用场。比如我们想知道一个函数完整的执行时间,那么我们可以编写另一个函数B,然后将函数A传递进去,在B的内部计算函数A的执行时间。编写函数B的好处就是下次还要用到的使用就可以直接调用了。但是如果我们在写函数A的时候就想实现计算这个函数A的执行时间(就是每次调用的时候都会计算执行时间),那有什么办法呢?这是@装饰器就起作用了,而且可以很简洁的表示出来

def B():
pass

@B
def A():
pass
'''
上面的代码相当于
A=B(A)
'''


二.通过代码来理解

1.函数的调用

函数在python中是可以作为变量,或者说作为实参传入一个函数的:

def func1(func):
print("Start func1")
func()
print("End func1")

def func2():
print("Start func2")
print("End func2")

func1(func2)


结果:


2.函数的嵌套

这一步,我们在升级一下。加一个函数的嵌套,说白了就是在一个函数中定义一个新的函数。

def func1(func):
print("This is func1")
def insidefunc():
print("This is the inside function")
func()
print("Inside function end")
print("func1 end\n")
return insidefunc

def func2():
print("This func2")
print("func2 end\n")

print("start:")
print("func2 name:", func2.__name__, "\n")

print("To decorate:")
func2 = func1(func2)

print("end:")
print("func2 name", func2.__name__, "\n")
func2()


能够理解以上代码,其实就基本理解装饰器了

他主要就是将func2变成另一个函数而已。

执行结果:



3.运用装饰器

好了我们开始运用装饰器吧

def func1(func):
print("This is func1")
def insidefunc():
print("This is inside function")
func()
print("Inside function end")
print("func1 end\n")
return insidefunc

@func1
def func2():
print("This is func2")
print("func2 end")

print("start:")
print("func2 name:", func2.__name__)

func2()


我们先来看一下执行效果:



从结果可以看到,当我们在修饰时,就已经调用好了修饰函数func1修饰了,之后在调用的时候就不在调用修饰函数func1了。这里要注意的是,我们在定义修饰函数时必须在内部定一个新的函数insidefunc,然后在这个新的函数中进行操作后,最后返回这个insidefunc,也就是说func2已经变成了insidefunc了

4.被修饰的函数传入参数

当然,我们的被修饰函数是可以传入函数的。只不过我们需要在修饰函数的内部函数insidefunc的()的参数与被修饰函数的参数数量一致就好。

def func1(func):
print("This is func1")
def insidefunc(a, b):
print("This inside function")
a = func(a, b)
print("Parameter from func:", a)
print("Inside function end")
print("func1 end\n")
return insidefunc

@func1
def func2(a, b):
print("This is func2")
print("func2 end")
return a + b

print("start")
func2(4, 5)




5.修饰函数传入参数

我们的修饰函数也是可以传入参数的

def func1(arg=True):
if arg:
def _func1(func):
print("This in _func1")
def insidefunc(a, b):
print("This is in _func1.insidefunc")
c = func(a, b)
return c
return insidefunc
return _func1
else:
def _wfunc1(func):
print("This is _wfunc1")
return func
return _wfunc1

@func1(True)
def func2(a, b):
print("This func2")
return a + b

@func1(False)
def func3(a, b):
print("This is func3")
return a * b

print(func2(4, 5))
print("\n")
print(func3(4, 5))




6.装饰器的连续套用

def func1(func):
def _func1(a):
print("This is _func1")
a = func(a)
return a * a
return _func1

def func2(func):
def _func2(a):
print("This is _func2")
a = func(a)
return a * 3
return _func2

@func1
@func2
def func3(a):
print("This is func3")
return a

print("Start:")
print(func3(1))
print(func3(2))




还有一些其他装饰器的用法,比如在类里面装饰函数,或者用类来装饰就不一一展开了

三.装饰器的主要用途

说了这么多,大家可能对装饰器到底在实际开发中有什么应用还是很困惑的。其实在实际的开发中,装饰器还是很常见的,而且用处还很大。

主要应用于几个方面:参数检查、统计时间、缓存、注册回调函数、函数加日志 、线程异步等等

举个例子多线程异步:

from threading import Thread
from functools import wraps

def async(func):
@wraps(func)
def async_func(*args, **kwargs):
func_hl = Thread(target=func, args=args, kwargs=kwargs)
func_hl.start()
return func_hl

return async_func

if __name__ == '__main__':
from time import sleep

@async
def print_somedata():
print('starting print_somedata')
sleep(2)
print('print_somedata: 2 sec passed')
sleep(2)
print('print_somedata: 2 sec passed')
sleep(2)
print('finished print_somedata')

@async
def _print_somedata():
print('starting _print_somedata')
sleep(2)
print('_print_somedata: 2 sec passed')
sleep(2)
print('_print_somedata: 2 sec passed')
sleep(2)
print('finished _print_somedata')

def main():
print_somedata()
print('back in main')
_print_somedata()
print('back in main')

main()




详细用途可以看看官方文档:https://wiki.python.org/moin/PythonDecoratorLibrary

好了,今天就到这。谢谢浏览。

有问题探讨加QQ:1043601529。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python