技术拾贝 | python装饰器介绍

在 Python 中,装饰器(Decorator) 是一种特殊的函数或类,用于动态修改或增强其他函数或类的行为,而无需直接修改其源代码。装饰器本质上是一个高阶函数(即接收函数作为参数并返回函数),通过 @ 语法糖(syntactic sugar)来简洁地应用。


装饰器的定义方式

装饰器的核心是一个可调用对象(函数或类),它接受一个函数作为输入,并返回一个新的函数(或类)。以下是定义装饰器的两种常见方式:

1. 函数装饰器(最常用)

装饰器本身是一个函数,它接收一个函数(被装饰的函数)作为参数,并返回一个新的函数(通常称为 wrapper)。

基本结构
def decorator(func):          # 1. 接收一个函数
    def wrapper(*args, **kwargs):  # 2. 定义包装函数
        # 在这里添加额外功能(如日志、计时、权限检查等)
        result = func(*args, **kwargs)  # 3. 调用原函数
        return result
    return wrapper            # 4. 返回包装后的函数

# 使用装饰器
@decorator
def target_function():
    print("Hello, World!")

# 调用被装饰的函数
target_function()  # 实际调用的是 wrapper()
示例:计算函数执行时间
import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)  # 执行原函数
        end = time.time()
        print(f"{func.__name__} 执行耗时: {end - start:.4f}秒")
        return result
    return wrapper

@timer
def slow_function(delay):
    time.sleep(delay)
    return "Done!"

slow_function(1)  # 输出: slow_function 执行耗时: 1.0002秒

运行结果


2. 类装饰器

装饰器也可以是一个类,通过实现 __call__ 方法使其可调用,从而装饰目标函数。

基本结构
class Decorator:
    def __init__(self, func):  # 初始化时接收被装饰的函数
        self.func = func

    def __call__(self, *args, **kwargs):  # 实例可调用时执行
        # 在这里添加额外功能
        result = self.func(*args, **kwargs)
        return result

# 使用装饰器
@Decorator
def target_function():
    print("Hello, World!")

target_function()  # 调用 __call__ 方法
示例:统计函数调用次数
class CountCalls:
    def __init__(self, func):
        self.func = func
        self.calls = 0

    def __call__(self, *args, **kwargs):
        self.calls += 1
        print(f"函数 {self.func.__name__} 被调用了 {self.calls} 次")
        return self.func(*args, **kwargs)

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

greet("Alice")  # 输出: 函数 greet 被调用了 1 次
greet("Bob")    # 输出: 函数 greet 被调用了 2 次

运行结果:

 3. 内置装饰器

Python 自带了一些常用的装饰器,通常用于特定的功能增强或元编程。

常见内置装饰器
装饰器作用
@property将方法变成属性调用(obj.x 而不是 obj.x()
@classmethod定义类方法(第一个参数是 cls,而非 self
@staticmethod定义静态方法(无 self 或 cls 参数)
@functools.lru_cache缓存函数结果,避免重复计算(常用于递归优化)
示例
class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property  # 将方法转为属性
    def radius(self):
        return self._radius

    @classmethod  # 类方法
    def from_diameter(cls, diameter):
        return cls(diameter / 2)

    @staticmethod  # 静态方法
    def pi():
        return 3.14159

# 使用
c = Circle.from_diameter(10)  # 类方法调用
print(c.radius)  # 输出: 5.0(通过属性访问)
print(Circle.pi())  # 输出: 3.14159(静态方法)

运行结果


装饰器的变种

1. 带参数的装饰器

如果装饰器本身需要参数,则需要三层嵌套函数

def repeat(n):           # 外层接收装饰器参数
    def decorator(func):  # 中层接收被装饰的函数
        def wrapper(*args, **kwargs):  # 内层包装逻辑
            for _ in range(n):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)  # 调用 repeat(3) 返回 decorator,再装饰 say_hello
def say_hello():
    print("Hello!")

say_hello()  # 输出 3 次 "Hello!"

运行结果:

2. 保留原函数信息(functools.wraps

装饰器会覆盖原函数的 __name____doc__ 等元信息,可以使用 @functools.wraps(func) 修复:

from functools import wraps

def log_calls(func):
    @wraps(func)  # 保留原函数的元信息
    def wrapper(*args, **kwargs):
        print(f"调用 {func.__name__},参数: {args}, {kwargs}")
        return func(*args, **kwargs)
    return wrapper

@log_calls
def add(a, b):
    """计算两数之和"""
    return a + b

print(add.__name__)  # 输出 "add"(不加 wraps 会输出 "wrapper")
print(add.__doc__)   # 输出 "计算两数之和"

运行结果:


总结

装饰器类型定义方式适用场景
函数装饰器def decorator(func): ...通用功能扩展(日志、计时、权限)
类装饰器class Decorator: def __call__需要维护状态的装饰逻辑
带参数的装饰器def decorator(args): ...动态调整装饰行为
保留元信息的装饰器@functools.wraps(func)避免函数名、文档被覆盖

装饰器是 Python 元编程的重要工具,广泛应用于 Web 框架(Flask/Django)、测试、日志、缓存等场景。合理使用可以让代码更简洁、可维护性更高!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值