Python之装饰器

装饰器

今天我们来学习以下Python里面的高阶函数,装饰器decorator;它是一种强大的工具,可以修改、扩展函数(方法)的行为,并且无需修改原函数(方法)的代码;身为高阶函数,必然有高级的地方,即函数可以作为参数传递,也可以当作返回值返回

别看上面写的一堆话,它的作用其实很简单

  • 代码复用,通用的功能抽象为装饰器
  • 代码解耦,核心逻辑和附加功能分离开
  • 动态扩展,运行时候修改函数的行为

下面就让我们进行实战以下,看看装饰器到底是个怎么回事

定义、使用装饰器

# 定义装饰器
def decorator(func):
 def wrapper(*args, **kwargs):
 # 在调用原始函数之前执行的操作
 print("Before calling the function")
 result = func(*args, **kwargs)
 # 在调用原始函数之后执行的操作
 print("After calling the function")
 return result
 return wrapper
# 使用装饰器
@decorator
def say_hello(name):
 return f"Hello, {name} "
print(say_hello("Michael"))
"""
Before calling the function
After calling the function
Hello, Michael 
"""

手动应用装饰器

# 定义装饰器
def decorator(func):
 def wrapper(*args, **kwargs):
 # 在调用原始函数之前执行的操作
 print("Before calling the function")
 result = func(*args, **kwargs)
 # 在调用原始函数之后执行的操作
 print("After calling the function")
 return result
 return wrapper
def say_hello(name):
 return f"Hello, {name} "
 
# 手动应用装饰器
decorated_function = decorator(say_hello)
print(decorated_function("Anna"))
"""
Before calling the function
After calling the function
Hello, Michael 
"""

带参数的装饰器

# 带参数的装饰器
# 外层函数接受装饰器参数
# 内层函数接受目标函数
def repart(num_times):
 def decorator(func):
 def wrapper(*args, **kwargs):
 for _ in range(num_times):
 result = func(*args, **kwargs)
 return result
 return wrapper
 return decorator
@repart(3)
def greet(name):
 print(f"Hello, {name}")
greet("Anna")
"""
Hello, Anna
Hello, Anna
Hello, Anna
"""

类装饰器

# 类装饰器
# 通过实现__call__方法来装饰函数
class Mydecorator:
 def __init__(self, func):
 self.func = func
 def __call__(self, *args, **kwargs):
 print("Before calling the function")
 result = self.func(*args, **kwargs)
 print("After calling the function")
 return result
@Mydecorator
def say_hello(name):
 return f"Hello {name}"
print(say_hello("John"))
"""
Before calling the function
After calling the function
Hello John
"""

保留函数的元信息

但是使用装饰器后,原始函数的元信息会被覆盖(__name__和__doc__等

解决办法就是下面的functools.wraps

# 保留函数的元信息
from functools import wraps
def my_decorator(func):
 @wraps(func)
 def wrapper(*args, **kwargs):
 print("Before calling the function")
 result = func(*args, **kwargs)
 print("After calling the function")
 return result
 return wrapper
@my_decorator
def say_hello(name):
 """Greet someone by name."""
 print(f"Hello, {name}!")
print(say_hello.__name__) # say_hello
print(say_hello.__doc__) # Greet someone by name.

当然了,有的同学会问,我可不可以使用两个、三个装饰器呢;答案是当然可以的;我们来看一下DeepSeek给出的例子

# 装饰器 1:日志记录
def log_decorator(func):
 def wrapper(*args, **kwargs):
 # 记录函数调用
 print(f"Log: Calling function {func.__name__} with args: {args}, kwargs: {kwargs}")
 # 调用原始函数
 result = func(*args, **kwargs)
 # 记录函数返回结果
 print(f"Log: Function {func.__name__} returned: {result}")
 return result
 return wrapper
# 装饰器 2:权限验证
def auth_decorator(func):
 def wrapper(*args, **kwargs):
 # 模拟权限检查
 user = "admin" # 假设当前用户是 admin
 if user == "admin":
 print("Auth: User is authorized.")
 # 调用原始函数
 result = func(*args, **kwargs)
 return result
 else:
 raise PermissionError("Auth: Unauthorized access.")
 return wrapper
# 装饰器 3:性能测试
def timing_decorator(func):
 import time
 def wrapper(*args, **kwargs):
 # 记录开始时间
 start_time = time.time()
 # 调用原始函数
 result = func(*args, **kwargs)
 # 记录结束时间
 end_time = time.time()
 # 计算并输出执行时间
 print(f"Timing: Function {func.__name__} took {end_time - start_time:.4f} seconds")
 return result
 return wrapper
# 应用多个装饰器
@log_decorator
@auth_decorator
@timing_decorator
def greet(name):
 # 模拟一个耗时操作
 import time
 time.sleep(1)
 return f"Hello, {name}!"
# 等价于
greet = log_decorator(auth_decorator(timing_decorator(greet)))
# 测试代码
if __name__ == "__main__":
 try:
 print(greet("Alice"))
 except PermissionError as e:
 print(e)

我们可以看下面的输出信息,首先是打印Log、其次是权限认证、时间;最后就是Log结束;没错通过输出信息我们可以看出来,多个装饰器的时候,执行顺序是从上到下的;返回的时候是从下到上

  • 当调用 greet("Alice") 时,装饰器会按照以下顺序执行:
    1. log_decoratorwrapper
    2. auth_decoratorwrapper
    3. timing_decoratorwrapper
    4. 原始函数 greet
  • 返回时,顺序相反:
    1. timing_decoratorwrapper
    2. auth_decoratorwrapper
    3. log_decoratorwrapper

下面我们来看一下多装饰器的执行流程

  • 调用greet("Alice")
    • 进入log_decoratorwapper,记录函数的调用
    • 进入auth_decoratorwapper,检查权限
    • 进入timing_decoratorwapper,记录开始时间
    • 最后调用原始函数greet
  • 返回结果流程
    • 原始函数greet返回结果
    • timing_decoratorwapper记录结束时间并输出执行时间
    • auth_decoratorwapper返回结果
    • log_decoratorwapper记录返回结果并输出
Log: Calling function wrapper with args: ('Alice',), kwargs: {}
Auth: User is authorized.
Timing: Function greet took 1.0002 seconds
Log: Function wrapper returned: Hello, Alice!
Hello, Alice!

装饰器就到这里了,这里只是简单的例子,具体还需要私底下找一些实例来进行操作,才能更好的记忆深刻

作者:小鑫仔原文地址:https://www.cnblogs.com/maoning/p/18785474

%s 个评论

要回复文章请先登录注册