Python 函数装饰器
一、装饰器有什么用
函数装饰器是修改其他函数的功能的函数,不用修改原来的函数就可以增加新的功能,并且可以大量复用代码。装饰器有助于让我们的代码更Pythonic,语义更加清晰!
二、函数装饰器举例
def logging_fuc(func):
def wrapper(*args, **Kwargs):
print('[log] this is a log')
return func(*args, **Kwargs)
return wrapper
def mywork():
print('I am doing my work!')
if __name__ == '__main__':
mywork = logging_fuc(mywork)
mywork()
结果:
[log] this is a log
I am doing my work!
分析:
具体逻辑是将原函数作为参数传递给一个新函数,新函数里面有一个内置函数,内置函数 先实现了额外功能,再在return中执行了传入的函数,最后这个logging_fuc 函数返回了内部函数。
装饰器通过将原函数名重新指向logging_fuc 的内部函数 wrapper ,所以有这样的逻辑顺序,先执行新功能,再执行原函数(指原mywork方法)。
以上是装饰器的原始形态,还有一个将mywork重新赋值的过程。在通常的表示中 装饰器常常不这么显示(因为太麻烦了!!)而是在mywork函数上方用@logging_func标示。如下
def logging_fuc(func):
def wrapper(*args, **Kwargs):
print('[log] this is a log')
return func(*args, **Kwargs)
return wrapper
@logging_fuc
def mywork():
print('I am doing my work!')
if __name__ == '__main__':
mywork()
结果:
[log] this is a log
I am doing my work!
这下装饰器的名字名副其实了,用@xxxx装饰了mywork!
三、含参数的函数装饰器
emmm赤裸裸的套娃,直接上例子
def logging_fuc(other_str='default'):
def decorator(func):
def wrapper(*args, **Kwargs):
print('[log] this is a log')
print(other_str)
return func(*args, **Kwargs)
return wrapper
return decorator
@logging_fuc(other_str='this is my work')
def mywork(work='count'):
print('I am doing my work!', work)
if __name__ == '__main__':
mywork()
结果:
[log] this is a log
this is my work
I am doing my work! count
首先装饰器logging_fuc 可以有参数,要理解通常额外的逻辑在最内层函数,logging_fuc参数可以被内层函数使用,现在从最外层函数开始看,logging_fuc返回了decorator,mywork指向decorator,dacorator运行是return 了 wrapper,mywork运行时指向了wrapper,最终mywork运行时实现了wrapper功能,最终func()在return时被调用,完成mywork原功能。
四、被装饰函数带返回值该如何处理
def logging_fuc(other_str='default'):
def decorator(func):
def wrapper(*args, **Kwargs):
print('[log] this is a log')
print(other_str)
res = func(*args, **Kwargs)
return res
return wrapper
return decorator
@logging_fuc(other_str='this is my work')
def mywork(work='count'):
print('I am doing my work!', work)
return True
if __name__ == '__main__':
res = mywork()
print(res)
结果:
[log] this is a log
this is my work
I am doing my work! count
True
这里最需要理解的就是,其实装饰器函数最内层return fuc()是带括号的,带括号意味着运行函数,之前在没有返回值的函数直接运行即可,现在有返回值,只需要在return之前先执行,用变量接着返回值,return 返回值即可。
五、函数装饰器缺点
函数装饰器的优点是可以拓展原函数内容,同时使用函数装饰器也有缺点,就是函数装饰器会使一些原函数的性质丢失。
def logging_fuc(other_str='default'):
def decorator(func):
def wrapper(*args, **Kwargs):
print('[log] this is a log')
print(other_str)
res = func(*args, **Kwargs)
return res
return wrapper
return decorator
@logging_fuc(other_str='this is my work')
def mywork(work='count'):
'''
:param work:
:return:
'''
print('I am doing my work!', work)
return True
if __name__ == '__main__':
res = mywork()
print('fun name:', mywork.__name__)
print('fun doc:', mywork.__doc__)
print(res)
结果:
[log] this is a log
this is my work
I am doing my work! count
fun name: wrapper
fun doc: None
True
函数名变成了内层函数函数名,原函数的注释也木得了。那么如何解决这个问题呢?
使用functiontools的装饰器
import functools
def logging_fuc(other_str='default'):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **Kwargs):
print('[log] this is a log')
print(other_str)
res = func(*args, **Kwargs)
return res
return wrapper
return decorator
@logging_fuc(other_str='this is my work')
def mywork(work='count'):
'''
:param work:
:return:
'''
print('I am doing my work!', work)
return True
if __name__ == '__main__':
res = mywork()
print('fun name:', mywork.__name__)
print('fun doc:', mywork.__doc__)
print(res)
结果:
[log] this is a log
this is my work
I am doing my work! count
fun name: mywork
fun doc:
:param work:
:return:
True
原函数的信息被正常输出了!
发表评论