[Python基础] 装饰器
·
LuYanFCP
装饰器是可调用的对象,其参数是另一个函数(被装饰函数)。装饰器可能会处理被装饰的函数,然后把它返回,或者替换成另一个函数或者可调用对象。
1@test
2def target():
3 print("run target function!")
其作用与以下代码一样
1def target():
2 print("run target function!")
3target = test(target) # 在test函数中,会加强函数或者替换函数
函数装饰器在导入模块时理解执行,而被装饰的函数只是在明确调用的时候才运行。
Python不需要声明变量,但是假定在函数定义体重赋值的变量是局部变量。这比javascript的行为好太多,javascript也不需要声明变量,但是如果忘记把变量声明为局部变量(使用var),可能会在不知请的时候获取到全局变量。
一个装饰器的例子—给程序打运行log
目标,每次程序运行都输出log,输出程序运行的时间,结果等等,将log输出到terminal中
1import time
2def log(func):
3 def ff(*args, **kwargs):
4 t0 = time.time()
5 run_time = time.asctime(time.localtime(t0))
6 res = func(*args, **kwargs)
7 cost = time.time() - t0
8 name = func.__name__
9 args_str = ', '.join(repr(arg) for arg in args) # repr转换为人阅读的方式
10 print('[{}] {}({})->{} cust_time={} s'.format(run_time, name, args_str, res, cost))
11 return res
12 return f
13
14@log
15def f(n):
16 if n <= 1:
17 return 1
18 return n * f(n-1)
19
20>> f(5)
21[Fri Mar 20 16:04:05 2020] f(1)->1 cust_time=0.0 s
22[Fri Mar 20 16:04:05 2020] f(2)->2 cust_time=0.0 s
23[Fri Mar 20 16:04:05 2020] f(3)->6 cust_time=0.000997304916381836 s
24[Fri Mar 20 16:04:05 2020] f(4)->24 cust_time=0.000997304916381836 s
25[Fri Mar 20 16:04:05 2020] f(5)->120 cust_time=0.000997304916381836 s
26120
以上的例子就实现了这个功能,但是这个功能还不够完全,因为不支持关键词参数,同时器还会遮盖被装饰函数的__name__和__doc__等属性引入入functools.wraps来协助装饰器。
1def log(func):
2 @functools.wraps(func)
3 def f(*args, **kwargs):
4 t0 = time.time()
5 run_time = time.asctime(time.localtime(t0))
6 res = func(*args, **kwargs)
7 cost = time.time() - t0
8 name = func.__name__
9 args_str = ', '.join(repr(arg) for arg in args) # repr转换为人阅读的方式
10 print('[{}] {}({})->{} cust_time={} s'.format(run_time, name, args_str, res, cost))
11 return res
12 return f
参数化装饰器
我们将此见到很多wrap引入参数去辅助,类如
1from functools import lru_cache
2@lru_cache(max_size=16)
3def f(n):
4 if n <= 1:
5 return 1
6 return n * f(n-1)
这个就等价于
1f = lru_cache(max_size=16)(f)
因此如果要添加参数必须要让wraper的函数在多一层,还是以上面的例子,这个时候,可以将fmt当作参数
1import functools, time
2fmt='[{}] {}({})->{} cust_time={} s'
3def log(fmt):
4 def log_f(func):
5 @functools.wraps(func)
6 def f(*args, **kwargs):
7 t0 = time.time()
8 run_time = time.asctime(time.localtime(t0))
9 res = func(*args, **kwargs)
10 cost = time.time() - t0
11 name = func.__name__
12 args_str = ', '.join(repr(arg) for arg in args) # repr转换为人阅读的方式
13 print(fmt.format(run_time, name, args_str, res, cost))
14 return res
15 return f
16 return log_f
参考资料
《流畅的python》