python 装饰器
装饰器的本质是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能。
装饰器返回值是一个函数;接收参数也是一个函数(参数是我们业务要执行的函数)。
一个简单示例
# 定义一个简单的装饰器
def a_new_decorator(a_func):def wrapTheFunction():print("before executing a_func()"a_func()print("after executing a_func()"return wrapTheFunctiondef a_function():print('main func')# 装饰器执行的过程
a_function = a_new_decorator(a_function)
a_function()
过程:装饰器把要执行的函数作为参数传给自己,在创建一个同名函数对象代替要执行的函数
使用@
@a_new_decorator
def a_function():print('main func')a_function()
# 执行效果同上
functools.wraps
functools.wraps保留原函数的名字和注释文档(docstring)
from functools import wraps# 定义一个装饰器
def a_new_decorator(a_func):@wraps(a_func)def wrapTheFunction():print("before executing a_func()"a_func()print("after executing a_func()"return wrapTheFunction
函数参数
参数可以通*args、**kwargs
from functools import wraps
def decorator_name(f):@wraps(f)def decorated(*args, **kwargs):if not can_run:return "Function will not run"return f(*args, **kwargs)return decorated@decorator_name
def func(msg:str):print(msg)return("Function is running")can_run = True
print(func("hahah"))
# Output: hahah
# Output: Function is running
带参数的装饰器
外层再套一个函数
from functools import wrapsdef logit(logfile='out.log'):def logging_decorator(func):@wraps(func)def wrapped_function(*args, **kwargs):log_string = func.__name__ + " was called"print(log_string)# 打开logfile,并写⼊内容with open(logfile, 'a') as opened_file:# 现在将⽇志打到指定的logfileopened_file.write(log_string + '\n')return wrapped_functionreturn logging_decorator
@logit()
def myfunc1():pass
myfunc1()
# Output: myfunc1 was called
# 现在⼀个叫做 out.log 的⽂件出现了,⾥⾯的内容就是上⾯的字符串
@logit(logfile='func2.log')
def myfunc2():passmyfunc2()
# Output: myfunc2 was called
# 现在⼀个叫做 func2.log 的⽂件出现了,⾥⾯的内容就是上⾯的字符串
装饰类
类也可以用来构建装饰器
class logit(object):def __init__(self,logfile='out.log'):self.logfile = logfile# __call__ :可以使用类名调用__call__函数的实现def __call__(self,func):log_string = func.__name__+" was called"print(log_string)with open(self.logfile,'a') as open_file:open_file.write(log_string+"\n")self.notify()def notify(self):# 打印日志pass
@logit()
def func1():pass
可以继承logit,扩展功能
# 来添加email的功能,保留原来的记录日志的功能
class email_logit(logit):def __init__(self, email='admin@myproject.com', *args, **kwargs)self.email = emailsuper(logit, self).__init__(*args, **kwargs)def notify(self):# 打印日志# send emil pass