python三大器之装饰器详解
目录
- 装饰器
- 总结
装饰器
讲装饰器之前要先了解两个概念:
- 对象引用 :对象名仅仅只是个绑定内存地址的变量
def func(): # 函数名仅仅只是个绑定内存地址的变量 print("i`m running") # 这是调用 func() # i`m running # 这是对象引用,引用的是内存地址 func2 = func print(func2 is func) # True # 通过引用进行调用 func2() # i`m running
- 闭包:定义一个函数A,然后在该函数内部再定义一个函数B,并且B函数用到了外边A函数的变量
def out_func(): out_a = 10 def inner_func(inner_x): return out_a + inner_x return inner_func out = out_func() print(out) # <function out_func.<locals>.inner_func at 0x7ff378af5c10> out_func返回的是inner_func的内存地址 print编程客栈(out(inner_x=2)) # 12
装饰器和闭包不同点在于:装饰器的入参是函数对象,闭包入参是普通数据对象
def decorator_get_function_name(func): """ 获取正在运行函数名 :return: """ def wrapper(*arg): """ wrapper :param arg: :return: """ print(f"当前运行方法名:{func.__name__} with params: {arg}") return func(*arg) return wrapper @decorator_get_function_name def test_func_add(x, y): print(x + y) @decorator_get_function_name def test_func_sub(x, y): print(x - y) test_func_add(1, 2) # 当前运行方法名:test_func_add with params: (1, 2) # 3 test_func_sub(3, 5) # 当前运行方法名:test_func_sub with params: (3, 5) # -2
常用于如鉴权校验,例如笔者会用于登陆校验:
def login_check(func): def wrapper(request, *args, **kwargs): if not request.session.get('login_status'): return HttpResponseRedirect('/api/login/') return func(request, *args, **kwargs) return wrapper @login_check def edit_config(): pass
装饰器内部的执行逻辑:
""" > 1. def login_check(func): ==>将login_check函数加载到内存 > .... > @login_check ==>此处已经在内存中将login_check这个函数执行了!;并不需要等edit_config()实例化调用 > 2. 上例@login_check内部会执行以下操作: > 2.1 执行login_check函数,并将 @login_check 下面的 函数(edit_config) 作为login_check函数的参数,即:@login_check 等价于 login_check(edit_config) > 2.2 内部就会去执行: def wrapper(*args): # 校验session... return func(request, *args, **kwargs) # func是参数,此时 func 等于 edit_config,此处相当于edit_config(request, *args, **kwargs) return wrapper # 返回的 wrapper,wrapper代表的是函数对象,非函数实例化对象 2.3 其实就是将原来的 edit_config 函数塞进另外一个函数中,另一个函数当中可以做一些操作;再执行edit_config 2.4 将执行完的 login_check 函数返回值(也就是 wrapper对象)将此返回值再重新赋值www.cppcns.com给新 edit_config,即: 2.5 新edit_config = def wrapper: # 校验session... return 原来edit_config(request, *args, **kwargs) > 3. 也就是新edit_config()=login_check(edit_config):wrapper(request, *args, **kwargs):return edit_config(request, *args, **kwargs) 有点绕,大家看步骤细细理解。 """
同样一个函数也可以使用多个装饰器进行装饰,执行顺序从上到下
from functools import wraps def w1(func): @wraps(fun编程客栈c) def wrapper(*args, **kwargs): print("这里是第一个校验") return func(*args, **kwargs) return wrapper def w2(func): @wraps(func) def wrapper(*args, **kwargs): print("这里是第二个校验") return func(*args, **kwargs) return wrapper def w3(func): def wrapper(*args, **kwargs):www.cppcns.com print("这里是第三个校验") return func(*args, **kwargs) return wrapper @w2 # 这里其实是w2(w1(f1)) @w1 # 这里是w1(f1) def f1(): print(f"i`m f1, at {f1}") @w3 def f2(): print(f"i`m f2, at {f2}") # ====================== 实例化阶段 ===================== f1() # 这里是第二个校验 # 这里是第一个校验 # i`m f1, at <function f1 at 0x7febc52f5e50> f2() # 这里是第三个校验 # i`m f2, at <function w3.<lo
有同学可能要好奇 为什么f1对象打印的是“<function f1 at 0x7febc52f5e50>”,f2对象打印的是“<function w3..wrapper at 0x7febc52f5f70>”(也就是步骤2.5造成的,赋的值是wrapper对象),这就跟w1和w2 内部wrapper使用的wraps装饰器有关系了。
wraps的作用是:被修饰的函数(也就是里面的func)的一些属性值赋值给修饰器函数(wrapper)包括元信息和“函数对象”等。
同时装饰器也可以接受参数:
def decorator_get_function_duration(enable): """ :param enable: 是否需要统计函数执行耗时 :return: """ print("this is decorator_get_function_duration") def inner(func): print('this is inner in decorator_get_function_duration') @wraps(func) def wrapper(*args, **kwargs): print('this is a wrapper in decorator_get_function_duration.inner') if enable: start = time.time() print(f"函数执行前:{start}") result = func(*args, **kwargs) print('[%s]`s enable was %s it`s duration : %.3f s ' % (func.__name__, enable, time.time() - start)) else: result = func(*args, **kwargs) return result return wrapper return inner def decorator_1(func): print('this is decorator_1') @wraps(func) def wrapper(*args, **kwargs): print('this is a wrapper in decorator_1') return func(*args, **kwargs) return wrapper def decorator_2(func): print('this is decorator_2') @wraps(func) def wrapper(*args, **kwargs): print('this is a wrapper in decorator_2') return func(*args, **kwargs) return wrapper @decorator_1 # 此处相当:decorator_1(decorator_2(decorator_get_function_duration(enable=True)(fun))) @decorator_2 # = decorator_2(decorator_get_function_duration(enable=True)(fun)) @decorator_get_function_duration(enable=True) # = decorator_get_function_duration(enable=True)(fun) def fun(): time.sleep(2) print("fun 执行完了~") fun() # ======== enable=False ============ """ this is decorator_get_function_duration this is inner in decorator_get_function_duration this is decorator_2 this is decorator_1 this is a wrapper in decorator_1 this is a wrapper in decorator_2 this is a wrapper in decorator_get_function_duration.inner fun 执行完了~ """ # ======== enable=True ============ """ this ishttp://www.cppcns.com decorator_get_function_duration this is inner in decorator_get_function_duration this is decorator_2 this is decorator_1 this is a wrapper in decorator_1 this is a wrapper in decorator_2 this is a wrapper in decorator_get_function_duration.inner 函数执行前:1634635708.648994 fun 执行完了~ [fun]`s enable was True it`s duration : 2.002 s """
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!
精彩评论