【教程】Python装饰器完全指南:从入门到精通


阿里云特惠 - 新用户专享

Python装饰器完全指南

装饰器是Python最强大的特性之一.本文从基础语法到高级应用,带你全面掌握装饰器.

第1步:理解函数是一等公民

# Python中函数可以像变量一样传递
def greet(name):
    return f"Hello, {name}!"

# 函数可以赋值给变量
say_hello = greet
print(say_hello("Alice"))  # Hello, Alice!

# 函数可以作为参数
def execute(func, arg):
    return func(arg)

execute(greet, "Bob")  # Hello, Bob!

# 函数可以嵌套定义
def outer():
    def inner():
        return "I'm inner"
    return inner

func = outer()
print(func())  # I'm inner

第2步:手写第一个装饰器

# 装饰器本质:接收函数作为参数,返回一个新函数
def my_decorator(func):
    '''
    装饰器函数
    参数func: 被装饰的原始函数
    返回: 包装后的新函数
    '''
    def wrapper(*args, **kwargs):
        # 函数执行前的操作
        print(f"准备执行: {func.__name__}")
        
        # 调用原始函数
        result = func(*args, **kwargs)
        
        # 函数执行后的操作
        print(f"执行完成: {func.__name__}")
        return result
    
    return wrapper

# 使用装饰器
@my_decorator
def say_hi():
    print("Hi!")

# 等价于: say_hi = my_decorator(say_hi)

say_hi()
# 输出:
# 准备执行: say_hi
# Hi!
# 执行完成: say_hi

第3步:带参数的装饰器

# 装饰器本身需要参数时,需要三层嵌套
def repeat(times):
    '''
    让函数重复执行指定次数的装饰器
    
    参数times: 重复执行次数
    '''
    def decorator(func):
        def wrapper(*args, **kwargs):
            results = []
            for i in range(times):
                print(f"第{i+1}次执行...")
                result = func(*args, **kwargs)
                results.append(result)
            return results
        return wrapper
    return decorator

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

results = greet("World")
# 输出:
# 第1次执行...
# 第2次执行...
# 第3次执行...
# results = ['Hello World', 'Hello World', 'Hello World']

第4步:实用装饰器案例

import time
import functools

# 1. 计时装饰器
def timer(func):
    '''计算函数执行时间'''
    @functools.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

# 2. 缓存装饰器(简易版)
def memoize(func):
    '''缓存函数结果,避免重复计算'''
    cache = {}
    
    @functools.wraps(func)
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    
    return wrapper

# 3. 重试装饰器
def retry(max_attempts=3, delay=1):
    '''失败时自动重试'''
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_attempts - 1:
                        raise
                    print(f"第{attempt+1}次失败: {e},{delay}秒后重试...")
                    time.sleep(delay)
        return wrapper
    return decorator

# 使用示例
@timer
@memoize
def fibonacci(n):
    '''计算斐波那契数列'''
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(30))  # 第一次较慢
print(fibonacci(30))  # 第二次从缓存读取,瞬间完成

第5步:类装饰器

# 用类实现装饰器
class CountCalls:
    '''统计函数被调用次数'''
    
    def __init__(self, func):
        functools.update_wrapper(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 hello():
    print("Hello!")

hello()  # 被调用了 1 次
hello()  # 被调用了 2 次
hello()  # 被调用了 3 次

总结

装饰器是Python的语法糖,核心是高阶函数+闭包.掌握装饰器,能让你的代码更加简洁,可复用.

发表评论