jling 2019-06-26
首先我们要知道在python,一切皆对象,函数也是一个对象
>>> def test(): ... return "Hello World"
有自己的id值,有type,有自己的值
>>> id(test) 140155005410568 >>> type(test) <class 'function'> >>> test <function test at 0x7f78614f9d08>
甚至可以赋值给其他变量
>>> test1 = test >>> test1() 'Hello World'
哪怕是当做参数传递给别的函数,也可以当做函数的返回值
>>> def foo(func): ... print(func) ... return func ... >>> test2 = foo(test) <function test at 0x7f78614f9d08> >>> test2() 'Hello World'
装饰器本质其实就是一个函数, 可以让其它函数不改动源代码的情况下增加其他新功能, 比如网站经常需要的权限校验等场景
def add(x, y): print(x+y) add(1,2)
现在我们有一个新需求, 计算代码执行时间
import time def add(x, y): start_time = time.time print(x+y) stop_time = time.time print("{func} spend {time} ".format(func = "add", time = stop_time-start_time)) add(1,2)
我们当然可以这么写, 但是一来修改了源代码可能会造成一些未知的错误, 二来如果我们有一百个函数, 这样写也不现实, 这就是我们装饰器出场的时候了.
import time def timmer(func): """ :param func: 被装饰的函数 :return: 一个计算函数运行时间的函数 """ def wrapper(*args, **kwargs): """ :param args:收集被装饰函数的参数 :param kwargs:收集被装饰函数的关键字参数 :return: """ start_time = time.time() # 让进程睡一秒 time.sleep(1) # 调用被装饰的函数 result = func(*args, **kwargs) stop_time = time.time() print("{func} spend {time} ".format(func = "add", time = stop_time-start_time)) return result return wrapper
def add(x, y): print(x,y) # 因为timmer返回的是wrapper函数对象,所以执行add()相当于执行wrapper() add = timmer(add) add(1,2)
@timmer def add(x, y): print(x,y) add(1,2)
这就是最基本的装饰器, 在不修改源代码的前提下为函数添加一个新功能, 调用时只需要在原函数上方添加一个 @deco_name , 在这里是@timmer
python还允许我们给装饰器带上函数
import time def timmer(flag): """ :param flag: 接收装饰器的参数 :return: """ def outer_wrapper(func): """ :param func: 接收被装饰的函数 :return: """ # 接收被装饰函数的参数 def wrapper(*args, **kwargs): """ :param args: 收集被装饰函数的参数 :param kwargs: 收集被装饰函数的关键字参数 :return: """ if flag == "true": start_time = time.time() # 调用被装饰的函数 result = func(*args, **kwargs) # 让进程睡一秒 time.sleep(1) stop_time = time.time() print("{func} spend {time} ".format(func="add", time=stop_time - start_time)) return result else: print("Unexpected ending") return wrapper return outer_wrapper
所谓的语法糖便是你不使用也可以完成任务,但是使用它可以让你的代码更简洁
@timmer(flag="false") def add(x, y): print(x, y) add(1,2)
当函数被多个装饰器装饰时,从里向外装饰
@a @b @c def func(): pass
相当于
func = a(b(c(func)))