0
点赞
收藏
分享

微信扫一扫

Python 修饰器的用法和技巧以及应用


装饰器(decorator):

  1. 定义了一个函数,想在运行时动态增加功能,又不想改动函数本身的代码。可以起到复用代码的功能,避免每个函数重复性编写代码,简言之就是拓展原来函数功能的一种函数
  2. 在python中,装饰器(decorator) 分为​​函数装饰器​​​和​​类装饰器​​两种。
  3. python中内置的@语言就是为了简化装饰器调用。

列出几个装饰器函数:import functools

  1. 打印日志:@log
  2. 检测性能:@performance
  3. 数据库事务:@transaction
  4. URL路由:@post(‘/register’)

例子

注意

  1. ​wrapper​​​函数的参数传入就是func的参数传入, 既可以使用通用的​​*args, **kw​​ 一星大斗师和二星大斗师入场, 也可以直接定义

a. 二层套娃

fun执行流程是 ​​Decorator→wrapper→fun​

# 先执行log(now), 返回wrapper
# 调用wrapper, 打印函数名
# 在调用now, 就是wrapper的输入信息
def log(func):
def wrapper(*args, **kw): # 这里得到func的参数
print("call %s():", func.__name__)
return func(*args, **kw) # 调用原始函数
return wrapper

# 相当于 now = log(now),
@log
def now():
print("123")

if __name__ == "__main__":
now()

b. 三层套娃

fun执行流程是 ​​Log→Decorator→wrapper→fun​

# 先执行log("execute"), 返回Decorator函数, 
# 在调用Decorator函数返回wrapper,
# 在调用wrapper打印信息, 返回func,
# 在调用func, 执行func
# 相当于三层嵌套
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator


@log('execute')
def now():
print('2015-3-25')

if __name__ == '__main__':
now()

c. fun信息传给wrapper后返回的函数对象成了wrapper

​@functools.wraps(func)​

import functools
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator


@log('execute')
def now():
print('2015-3-25')
print(now.__name__)
# wrapper 这是因为这个函数执行完, 最终返回的是wrapper的函数指针,
# 逻辑就是log(text)(now), log(text)返回decorator再返回wrapper, 因此这里就成这了,
# 解决的方法就是把原始函数now的__name__等属性完全赋值到wrapper()函数中即可,

# 解决方案见下面

def log3(func):
@functools.wraps(func) # 把func的信息放入wrapper中
def wrapper(*args, **kw):
print('%s():' % (func.__name__))
return func(*args, **kw)
return wrapper

def log2(text):
def decorator(func):
@functools.wraps(func) # 把func的信息放入wrapper中
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator

@log2('execute')
@log3
def now2():
print('hello world')
print(now2.__name__)

if __name__ == '__main__':
now()
print("------------------")
now2()

应用

a. 函数执行时间

import time
import functools

# 不带参数的二层套娃
def timeCost(func):
@functools.wraps(func)
def log_time(*args, **kw):
t0 = time.time()
func(*args, **kw)
t1 = time.time()
print(f"function:{func.__name__}, time cost :{t1-t0}")
return t1-t0
return log_time

# 带参数的三层套娃
def timeCost2(unit):
def decorator(func):
@functools.wraps(func)
def log_time(*args, **kw):
t0 = time.time()
func(*args, **kw)
t1 = time.time()
print(f"function:{func.__name__}, time cost :{t1-t0} {unit}")
return t1-t0
return log_time
return decorator

@timeCost
@timeCost2("s") # 多修饰时, 先执行接近函数的, 因此先带ms, 然后在带
def test(t):
time.sleep(t)
if __name__ == '__main__':
test(3)


举报

相关推荐

0 条评论