装饰器
今天我们来学习以下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") 时,装饰器会按照以下次序执行:
- log_decorator 的 wrapper。
- auth_decorator 的 wrapper。
- timing_decorator 的 wrapper。
- 原始函数 greet。
- 返回时,次序相反:
- timing_decorator 的 wrapper。
- auth_decorator 的 wrapper。
- log_decorator 的 wrapper。
下面我们来看一下多装饰器的执行流程
- 调用greet("Alice")
- 进入log_decorator的wapper,记载函数的调用
- 进入auth_decorator的wapper,检查权限
- 进入timing_decorator的wapper,记载开始时间
- 最后调用原始函数greet
- 返回结果流程
- 原始函数greet返回结果
- timing_decorator的wapper记载结束时间并输出执行时间
- auth_decorator的wapper返回结果
- log_decorator的wapper记载返回结果并输出
- 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!
复制代码 装饰器就到这里了,这里只是简单的例子,具体还需要私底下找一些实例来进行操作,才能更好的记忆深刻
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |