我们在编写日常的开发过程中,代码中经常需要记录日志,比如编写一个函数,在函数的入口和出口需要记录函数的入参、出参和返回值等信息。如果我们用的是C++进行开发,就需要在函数的入口和该函数的出口都要添加日志记录的代码,比如:
void TestFunciton()
{
FunctionStart();
// do something
FunctionComplete();
}
其中FunctionStart和FunctionComplete分别为函数入口和出口信息添加日志的宏定义。这样的话,每个函数都需要添加类似的日志记录的代码,显得即多余又必须。
但是在python中,我们就可以避免这样的尴尬了,因为在python中我们有函数装饰器。那么什么是函数装饰器?又该怎么用呢?
简单点说,函数装饰器,就是一个可以修改其他函数功能的函数,来看下面的例子:
def coding():
return "I am coding"
def start_work(func):
print("Wait for work start time...")
print(func())
print("Work overtime...")
start_work(coding)
#output:Wait for work start time...
# I am coding
函数start_work相当于对coding函数进行了封装,在执行coding函数前增加了等待工作开始和下班后加班的操作,这就已经是一个简单的函数装饰器了。我们稍微改造一下这个装饰器,让它更合理一些:
def work_decorator(func):
def working():
print("Wait for work start time...")
func()
print("Work overtime...")
return working
def coding():
print("I am coding")
coding = work_decorator(coding)
coding()
#output:Wait for work start time...
# I am coding
# Work overtime...
进一步的,我们可以使用函数修饰符:
def work_decorator(func):
def working():
print("Wait for work start time...")
func()
print("Work overtime...")
return working
@work_decorator
def coding():
print("I am coding")
coding()
但是,此时如果我们输出coding.name,就会得到working,这是因为working替代了coding函数,重写了函数名,这并不是我们想要的结果,可以使用functools.wraps来解决这个问题:
from functools import wraps
def work_decorator(func):
@wraps(func)
def working():
print("Wait for work start time...")
func()
print("Work overtime...")
return working
@work_decorator
def coding():
print("I am coding")
在回到我们一开始遇到的问题,如果使用函数装饰器就很好解决了:
from functools import wraps
def work_decorator(func):
@wraps(func)
def working():
print("Function {0} entry".format(func.__name__))
func()
print("Function {0} return".format(func.__name__))
return working
@work_decorator
def coding():
print("I am coding")
coding()
#output:Function coding entry
# I am coding
# Function coding return