开发者

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 
"""

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新开发

开发排行榜