定义
给已有函数增加额外功能的函数。其本质上就是一个闭包函数。
特点
1. 不修改已有函数的源代码(无风险)
2. 不修改已有函数的调用方式(无风险)
3. 给已有函数增加额外的功能(只需要关注额外增加的部分)
语法
1. 定义一个装饰器
2. 在目标函数上使用装饰器
通过@装饰器名称 放在定义目标函数上一行,就完成对已有函数的装饰操作
示例
1 ''' 2 定义: 给已有函数增加额外功能的函数。其本质上就是一个闭包函数。 3 4 特点 5 1. 不修改已有函数的源代码(无风险) 6 2. 不修改已有函数的调用方式(无风险) 7 3. 给已有函数增加额外的功能(只需要关注额外增加的部分) 8 ''' 9 10 11 # 1. 定义一个装饰器,本质上就是闭包 12 def decorator(func): 13 def wrapper(*args, **kwargs): 14 print("Before function execution") 15 result = func(*args, **kwargs) 16 print("After function execution") 17 return result 18 19 return wrapper 20 21 22 # 2. 使用装饰器 23 @decorator 24 def my_function(): 25 print("Inside my_function") 26 27 28 ''' 29 3. 执行被装饰方法,验证装饰器是否生效 30 输出: 31 Before function execution 32 Inside my_function 33 After function execution 34 35 ''' 36 my_function()
这个示例中,decorator是一个装饰器函数,它接受一个函数作为参数,返回一个新的函数wrapper。wrapper函数会在被装饰的函数my_function执行前后打印一些信息。最后,通过使用@decorator语法将decorator应用到my_function上。
装饰器的流程图
装饰器本质上是闭包。只不过要求外部函数的参数必须是函数,实参是目标函数的引用。内部函数内部必须调用目标函数,内部函数形参列表要包含目标函数的形参列表,如果闭包函数有且只有一个参数,那必须是函数类型,这样定义的函数才是装饰器。。
实际执行过程如下:
1. 先按要求定义一个闭包
2. 以目标函数为参数,调用外部函数得到闭包函数即内部函数的引用
3. 调用闭包函数即内部函数。内部函数会在执行目标函数前后增加扩展功能。这个扩展功能就是对目标函数的装饰。类似于java装的AOP切面
使用场景
装饰器可以用于很多场景,例如记录函数执行时间、缓存函数结果、验证用户权限等。下面是几个常见的装饰器示例:
1. 记录函数执行时间的装饰器
1 import time 2 3 4 def timer(func): 5 def wrapper(*args, **kwargs): 6 start_time = time.time() 7 result = func(*args, **kwargs) 8 end_time = time.time() 9 execution_time = end_time - start_time 10 print("Execution time: {} seconds".format(execution_time)) 11 return result 12 13 return wrapper 14 15 16 @timer 17 def my_function(): 18 time.sleep(1) 19 20 21 my_function()
2. 缓存函数结果的装饰器
1 from functools import lru_cache 2 3 4 @lru_cache(maxsize=None) 5 def fibonacci(n): 6 if n <= 1: 7 return n 8 else: 9 return fibonacci(n - 1) + fibonacci(n - 2) 10 11 12 print(fibonacci(10))
这段代码使用了Python标准库中的functools
模块中的lru_cache
装饰器来优化斐波那契数列的计算。让我逐步解释这段代码的每个部分:
-
首先,代码导入了
functools
模块中的lru_cache
装饰器。 -
@lru_cache(maxsize=None)
这行是一个装饰器,应用在fibonacci
函数上。lru_cache
是"Least Recently Used Cache"(最近最少使用缓存)的缩写,它是一种用于缓存函数调用结果的方法。maxsize=None
表示缓存的大小没有限制,可以存储所有不同参数的函数调用结果。 -
def fibonacci(n):
声明了一个名为fibonacci
的函数,它接受一个整数参数n
,代表斐波那契数列的索引。 -
在函数内部,通过递归来计算斐波那契数列的第
n
个数。如果n
小于等于1,直接返回n
作为结果。 -
如果
n
大于1,递归地调用fibonacci(n - 1)
和fibonacci(n - 2)
,然后将它们的结果相加,从而计算出第n
个斐波那契数。 -
在函数内部的递归调用中,由于应用了
lru_cache
装饰器,先前计算过的结果会被缓存起来,以避免重复计算。 -
最后,
print(fibonacci(10))
调用了fibonacci
函数并打印 [Cannot read properties of undefined (reading 'status')]
3. 验证用户权限的装饰器
1 def require_permission(permission): 2 def decorator(func): 3 def wrapper(*args, **kwargs): 4 # 检查用户权限 5 if has_permission(permission): 6 # if permission == "admin": 7 return func(*args, **kwargs) 8 else: 9 raise PermissionError("You don't have permission to access this resource") 10 11 return wrapper 12 13 return decorator 14 15 16 @require_permission("admin") 17 def delete_user(user_id): 18 # 模拟删除用户 19 pass 20 21 22 def has_permission(permission): 23 print(permission) 24 return False # 模拟没有权限 25 26 27 delete_user(123)
多个装饰器执行顺序
多个装饰器的执行顺序是从内到外依次应用的,即最靠近被装饰函数的装饰器首先执行,然后依次向外执行。
让我通过一个示例来详细解释这个过程。
假设有两个装饰器:decorator1
和 decorator2
,以及一个被装饰的函数 my_function
。它们的定义如下:
1 def decorator1(func): 2 def wrapper(*args, **kwargs): 3 print("Decorator 1: Before function call") 4 result = func(*args, **kwargs) 5 print("Decorator 1: After function call") 6 return result 7 8 return wrapper 9 10 11 def decorator2(func): 12 def wrapper(*args, **kwargs): 13 print("Decorator 2: Before function call") 14 result = func(*args, **kwargs) 15 print("Decorator 2: After function call") 16 return result 17 18 return wrapper 19 20 21 @decorator1 22 @decorator2 23 def my_function(): 24 print("my_function is called") 25 26 27 ''' 28 输出: 29 Decorator 1: Before function call 30 Decorator 2: Before function call 31 my_function is called 32 Decorator 2: After function call 33 Decorator 1: After function call 34 ''' 35 my_function()
现在,让我们逐步解释代码和装饰器的执行顺序:
-
首先,
my_function
被传递给decorator2
装饰器,相当于decorator2(my_function)
。在decorator2
内部,它的wrapper
函数包装了my_function
。 -
当
my_function
被调用时,实际上是调用了decorator2
内部的wrapper
函数。这将输出 "Decorator 2: Before function call",然后调用原始的my_function
。 -
在
decorator2
的wrapper
函数内部,my_function
被调用,输出 "my_function is called"。 -
调用完成后,
decorator2
的wrapper
函数继续执行,输出 "Decorator 2: After function call",然后将控制权返回给decorator1
。 -
现在,
decorator1
被应用于已经被decorator2
包装过的my_function
(即decorator1(wrapper(my_function))
)。 -
在
decorator1
的wrapper
函数内部,输出 "Decorator 1: Before function call",然后调用已经被decorator2
和decorator1
包装过的函数。 -
同样地,输出 "my_function is called"。
-
调用完成后,
decorator1
的wrapper
函数继续执行,输出 "Decorator 1: After function call"。
综上所述,装饰器的执行顺序是从最靠近被装饰函数的装饰器开始,然后逐步向外执行。在示例中,先执行 decorator2
,再执行 decorator1
。
调用 my_function()
会产生以下输出:
Decorator 1: Before function call Decorator 2: Before function call my_function is called Decorator 2: After function call Decorator 1: After function call
总结:
1. 离被装饰函数最近的装饰器先装饰
2. 然后外面的装饰器再进行装饰(此时是已经装饰的函数)
3. 总的顺序为 内 --> 外,进行层层加工、装饰
标签:function,函数,wrapper,my,装饰,def From: https://www.cnblogs.com/allenxx/p/17659621.html