详细分析Python装饰器(附Demo)

前言

装饰器类似Java的切点切面增强

推荐阅读:

  1. 详细分析Spring中的@Around注解(附Demo)
  2. java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
  3. Spring框架从入门到学精(全)

Python实战代码如下:

在这里插入图片描述

1. 基本知识

装饰器是Python语言中的一种高级功能,它允许将一个函数或者类“装饰”(即修改或增强)其他函数或者类的行为。装饰器本质上是一个可调用的对象,它接受一个函数或者类作为输入,并返回一个新的函数或者类

作用优点缺点
代码重用: 装饰器可以用来包装重复使用的功能或逻辑,提高代码的重用性

代码简洁: 装饰器可以将一些与主要逻辑无关的代码分离出来,使主要代码更加简洁易读

横切关注点(Cross-cutting Concerns): 装饰器可以用来处理与业务逻辑无关但又必须存在于多处的功能,例如日志记录、性能检测、权限验证等

动态增加功能: 装饰器可以在不修改被装饰对象的情况下,动态地增加新的功能或行为
提高代码的复用性和可维护性

使代码更加简洁,易于理解

允许动态地添加或修改对象的行为,而无需修改其原始定义
可能会增加代码的复杂性,特别是在使用多个装饰器的情况下

装饰器可能会改变被装饰对象的原始行为,导致难以调试

2. 无参装饰器

通过Demo了解如何增强

# 定义一个简单的装饰器函数 simple_decorator,接受一个函数作为参数
def simple_decorator(func):
    # 定义一个内部函数 wrapper,用于包装被装饰的函数
    def wrapper():
        print("Before calling the function")  # 在调用被装饰函数之前打印信息
        func()  # 调用被装饰的函数
        print("After calling the function")  # 在调用被装饰函数之后打印信息
    return wrapper  # 返回内部函数 wrapper

# 使用装饰器 simple_decorator 对 say_hello 函数进行装饰
@simple_decorator
def say_hello():
    print("执行一次say_hello")  # 打印信息,表示 say_hello 函数被执行了一次

# 调用被装饰后的 say_hello 函数,实际上会在函数执行前后打印额外的信息
say_hello()

截图如下:

在这里插入图片描述

3. 有参装饰器

额外添加了一个内部函数 decorator,它负责接收被装饰函数,并返回一个装饰器函数 wrapper。这种设计更符合装饰器的惯用方式,即装饰器函数接受参数(在这里是 n),然后返回一个装饰器函数,该装饰器函数再接受被装饰的函数,并返回一个新的函数(或者对原函数进行修改)

# 定义一个装饰器函数 repeat,接受一个参数 n,表示要重复执行的次数
def repeat(n):
    # 定义一个内部函数 decorator,该函数接受被装饰的函数作为参数 func
    def decorator(func):
        # 定义一个内部函数 wrapper,用于包装被装饰的函数,以实现重复执行的功能
        def wrapper(*args, **kwargs):
            # 使用 for 循环执行被装饰的函数 n 次
            for _ in range(n):
                func(*args, **kwargs)  # 调用被装饰的函数
        return wrapper  # 返回 wrapper 函数
    return decorator  # 返回 decorator 函数

# 使用装饰器 repeat(3) 对 greet 函数进行装饰,表示要重复执行 3 次
@repeat(3)
def greet(name):
    print(f"Hello, {name}!")  # 打印输出问候语

# 调用被装饰后的 greet 函数,实际上会重复打印三次问候语
greet("码农研究僧")

截图如下:

在这里插入图片描述

以下为错误显示:

def repeat(n):
    def wrapper(*args, **kwargs):
        func(*args, **kwargs)
    return wrapper
        


@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("码农研究僧")

装饰器 repeat 的内部函数 wrapper 中使用了 func(*args, **kwargs) 来调用被装饰的函数,但是在 repeat 函数内部并没有定义 func,因此会引发错误。正确的方式是在 repeat 内部定义一个参数来接收被装饰函数,并在 wrapper 中使用该参数来调用被装饰函数

4. 多个装饰器

以下代码整体逻辑如下:

  1. greet("manong") 被 bold 装饰器装饰,变成 bold(uppercase(greet))("manong")
  2. 首先 uppercase(greet) 被调用,得到大写的字符串 "HELLO, MANONG!"
  3. bold 装饰器再次被调用,将大写的字符串用 <b> 和 </b> 标签包裹起来,得到 <b>HELLO, MANONG!</b>
  4. 最终的结果被打印输出
# 定义装饰器 uppercase,将被装饰函数的返回值转换为大写
def uppercase(func):
    def wrapper(*args, **kwargs):
   		print(2)
        # 调用被装饰函数,并将结果转换为大写
        result = func(*args, **kwargs)
        print(3)
        return result.upper()
    return wrapper

# 定义装饰器 bold,将被装饰函数的返回值用 <b> 和 </b> 标签包裹起来
def bold(func):
    def wrapper(*args, **kwargs):
    	print(1)
        # 调用被装饰函数,并用 <b> 和 </b> 标签包裹返回结果
        result = func(*args, **kwargs)
        print(4)
        return f"<b>{result}</b>"
    return wrapper

# 先应用 bold 装饰器,再应用 uppercase 装饰器
@bold
@uppercase
def greet(name):
    return f"Hello, {name}!"

# 调用 greet 函数,并输出结果
print(greet("manong"))

截图如下:

在这里插入图片描述

当函数 greet 被装饰时, uppercase 装饰器会先执行,然后是 bold 装饰器。这意味着 uppercase 装饰器的 wrapper 函数会先被调用,然后是 bold 装饰器的 wrapper 函数

  • 29
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农研究僧

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值