【Python高级特性】装饰器

1. 装饰器(Decorator)

装饰器是 Python 的一个强大特性,用于在不修改原函数代码的情况下,动态地扩展或修改函数或方法的行为。它们广泛应用于日志记录、权限验证、性能监控等场景。

使用场景:

  • 日志记录:在函数执行前后添加日志信息,以便调试和追踪函数的调用情况。
  • 性能计数:计算函数执行时间,以优化代码性能。
  • 权限验证:在函数执行前检查用户权限,确保只有授权用户才能执行某些操作。
  • 事务处理:在数据库操作前后自动管理事务的开始和结束,确保数据一致性。
1.1 基本装饰器

概念

  • 装饰器是一种高阶函数,接受一个函数作为参数,并返回一个新的函数。

语法

  • 使用 @decorator_name 语法糖,将装饰器应用于函数。

示例

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Before function execution")
        result = func(*args, **kwargs)
        print("After function execution")
        return result
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

输出

Before function execution
Hello!
After function execution

解释

  • @my_decorator 等价于 say_hello = my_decorator(say_hello)
  • 装饰器 my_decorator 包装了原始函数 say_hello,在执行前后添加了打印语句。
1.2 带参数的装饰器

概念

  • 装饰器本身需要接受参数,需使用多层嵌套函数。

实现方式

  • 外层函数接收装饰器参数,返回中间层装饰器函数,该函数接收被装饰函数,最终返回包装函数。

示例

def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(times=3)
def say_hello():
    print("Hello!")

say_hello()

输出:

Hello!
Hello!
Hello!

解释

  • @repeat(times=3) 等价于 say_hello = repeat(times=3)(say_hello)
  • 外层 repeat 函数接收参数 times,返回内部装饰器 decorator
1.3 类装饰器

概念

  • 装饰器可以应用于类,不仅限于函数。
  • 类装饰器接收一个类作为参数,并返回一个修改后的类。

示例

def add_method(cls):
    def new_method(self):
        print("New method added to the class")
    cls.new_method = new_method
    return cls

@add_method
class MyClass:
    def original_method(self):
        print("Original method")

obj = MyClass()
obj.original_method()
obj.new_method()

输出:

Original method
New method added to the class

解释

  • 装饰器 add_method 动态地向类 MyClass 添加了一个新方法 new_method
1.4 内置装饰器

Python 提供了几个内置装饰器,常用于类方法和属性的定义。

  • @staticmethod: 定义静态方法,不需要类实例作为第一个参数。将方法定义为静态方法,允许在不实例化类的情况下调用。静态方法通常用于操作不依赖于类实例的数据。
class MyClass:
    @staticmethod
    def static_method():
        print("This is a static method")

MyClass.static_method()  # 无需实例调用
  • @classmethod: 定义类方法,第一个参数是类本身 (cls)。将方法定义为类方法,方法的第一个参数是类本身(cls),而不是实例。类方法常用于创建类的实例或修改类级别的状态。
class MyClass:
    @classmethod
    def class_method(cls):
        print(f"This is a class method of {cls}")

MyClass.class_method()
  • @property: 将方法转换为只读属性,实现属性的封装与控制。将方法转换为属性,允许使用属性访问的语法调用方法。这种方式常用于将getter方法转换为只读属性,简化属性访问。
class MyClass:
    def __init__(self, value):
        self._value = value

    @property
    def value(self):
        return self._value

obj = MyClass(10)
print(obj.value)  # 访问为属性
# obj.value = 20  # 抛出 AttributeError
1.5 装饰器的最佳实践
  • 保持装饰器的通用性:尽量让装饰器适用于不同类型的函数或方法。
  • 使用 functools.wraps:保留被装饰函数的元数据(如名称、文档字符串)。
import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("Before")
        result = func(*args, **kwargs)
        print("After")
        return result
    return wrapper
  • 避免装饰器堆叠复杂性:装饰器嵌套过多时,可能导致调试困难,建议保持装饰器逻辑简单。
  • 尽量使用标准库提供的装饰器:如 @staticmethod, @classmethod, @property 等,遵循 Python 的惯用用法。
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

可口的冰可乐

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

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

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

打赏作者

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

抵扣说明:

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

余额充值