🎨 Python装饰器完全指南:从入门到精通

Python装饰器是Python中最强大且优雅的特性之一,它允许你在不修改原函数代码的情况下,给函数添加额外的功能。本文将从基础概念到高级应用,带你全面掌握装饰器。

一、什么是装饰器?

装饰器本质上是一个高阶函数,它接收一个函数作为参数,并返回一个新的函数。装饰器的语法使用 @ 符号,放在函数定义之前。

# 一个简单的装饰器示例
def my_decorator(func):
    def wrapper():
        print("函数执行前")
        func()
        print("函数执行后")
    return wrapper

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

say_hello()
# 输出:
# 函数执行前
# Hello!
# 函数执行后

二、带参数的装饰器

实际应用中,被装饰的函数通常带有参数。我们需要让装饰器能够处理任意参数:

def decorator_with_args(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数: {func.__name__}")
        print(f"位置参数: {args}")
        print(f"关键字参数: {kwargs}")
        result = func(*args, **kwargs)
        print(f"函数返回值: {result}")
        return result
    return wrapper

@decorator_with_args
def add(a, b):
    return a + b

add(3, 5)
# 输出函数名、参数和返回值

三、装饰器本身带参数

有时候我们希望装饰器本身也能接收参数,这时需要嵌套三层函数:

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

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

greet("Alice")
# 会打印三次 "Hello, Alice!"

四、类装饰器

除了函数装饰器,Python还支持使用类作为装饰器:

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.count = 0
    
    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"{self.func.__name__} 被调用了 {self.count} 次")
        return self.func(*args, **kwargs)

@CountCalls
def say_hi():
    print("Hi!")

say_hi()  # 被调用了 1 次
say_hi()  # 被调用了 2 次

五、常用内置装饰器

1. @property - 将方法转为属性

class Circle:
    def __init__(self, radius):
        self._radius = radius
    
    @property
    def area(self):
        return 3.14159 * self._radius ** 2
    
    @property
    def radius(self):
        return self._radius
    
    @radius.setter
    def radius(self, value):
        if value < 0:
            raise ValueError("半径不能为负数")
        self._radius = value

c = Circle(5)
print(c.area)      # 像访问属性一样访问方法
print(c.radius)    # 获取半径
c.radius = 10      # 设置半径

2. @staticmethod 和 @classmethod

class MyClass:
    class_var = "类变量"
    
    @staticmethod
    def static_method():
        print("静态方法,不需要self或cls")
    
    @classmethod
    def class_method(cls):
        print(f"类方法可以访问: {cls.class_var}")

MyClass.static_method()  # 直接通过类调用
MyClass.class_method()

3. @functools.wraps - 保留原函数信息

from functools import wraps

def proper_decorator(func):
    @wraps(func)  # 保留原函数的元数据
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@proper_decorator
def example():
    """这是example的文档"""
    pass

print(example.__name__)  # 输出: example (不是wrapper)
print(example.__doc__)   # 输出: 这是example的文档

六、实际应用案例

1. 计时装饰器

import time
from functools import wraps

def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - start
        print(f"{func.__name__} 执行时间: {elapsed:.4f}秒")
        return result
    return wrapper

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

slow_function()

2. 缓存装饰器 (Memoization)

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# 第一次计算较慢,后续直接从缓存读取
print(fibonacci(100))  # 瞬间完成

七、多个装饰器叠加

装饰器可以叠加使用,执行顺序是从下往上:

@decorator_a
@decorator_b
@decorator_c
def my_func():
    pass

# 等价于:
# my_func = decorator_a(decorator_b(decorator_c(my_func)))

八、总结

装饰器是Python中实现面向切面编程(AOP)的利器,能让你的代码更加简洁、可复用。掌握装饰器,是成为Python高级开发者的必经之路!

关键要点:

  • 基础语法:@decorator 放在函数定义前
  • 带参数的装饰器:需要三层嵌套函数
  • 类装饰器:实现 __call__ 方法
  • 常用内置:@property, @staticmethod, @classmethod, @wraps
  • 应用场景:日志记录、性能计时、权限检查、缓存等

本文内容由AI生成,仅供学习参考。

posted @ 2026-03-23 01:17  码小小小仙  阅读(2)  评论(0)    收藏  举报