全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-19 8 分钟 ✍️ juanwangdev

Python 类装饰器

类装饰器通过实现 __call__ 方法使类实例可像函数一样被调用,适合需要维护状态的装饰器场景。

基本结构

Python
from functools import wraps


class CountCalls:
    "统计函数调用次数的装饰器"

    def __init__(self, func):
        self.func = func
        self.count = 0
        wraps(func)(self)  # 保留函数元信息

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"Call #{self.count} of {self.func.__name__}")
        return self.func(*args, **kwargs)


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


say_hello()  # Call #1 of say_hello
say_hello()  # Call #2 of say_hello
say_hello()  # Call #3 of say_hello
print(f"Total calls: {say_hello.count}")  # Total calls: 3

带参数的类装饰器

Python
class Retry:
    "重试装饰器:失败后自动重试"

    def __init__(self, max_attempts=3, exceptions=(Exception,)):
        self.max_attempts = max_attempts
        self.exceptions = exceptions

    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(1, self.max_attempts + 1):
                try:
                    return func(*args, **kwargs)
                except self.exceptions as e:
                    if attempt == self.max_attempts:
                        raise
                    print(f"Attempt {attempt} failed: {e}, retrying...")
        return wrapper


@Retry(max_attempts=3, exceptions=(ValueError, ConnectionError))
def fetch_data(url):
    import random
    if random.random() < 0.7:
        raise ValueError("Network error")
    return f"Data from {url}"

装饰类

类装饰器也可以用来装饰整个类:

Python
class Singleton:
    "单例装饰器"

    def __init__(self, cls):
        self.cls = cls
        self.instance = None

    def __call__(self, *args, **kwargs):
        if self.instance is None:
            self.instance = self.cls(*args, **kwargs)
        return self.instance


@Singleton
class Database:
    def __init__(self, name):
        self.name = name
        print(f"Creating database: {name}")


db1 = Database("prod")  # Creating database: prod
db2 = Database("dev")    # 不会创建新实例
print(db1 is db2)  # True

添加属性和方法

类装饰器可以为被装饰对象添加额外功能:

Python
class Memoize:
    "缓存装饰器:记忆函数返回值"

    def __init__(self, func):
        self.func = func
        self.cache = {}
        wraps(func)(self)

    def __call__(self, *args):
        if args not in self.cache:
            self.cache[args] = self.func(*args)
        return self.cache[args]

    def clear_cache(self):
        "添加缓存清理方法"
        self.cache.clear()
        print("Cache cleared")


@Memoize
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)


print(fibonacci(100))      # 快速计算
fibonacci.clear_cache()     # 清理缓存

与函数装饰器对比

特性函数装饰器类装饰器
状态维护需闭包或nonlocal直接用实例属性
复杂度简单场景更简洁复杂逻辑更清晰
可扩展性添加方法困难可定义多个方法
可读性嵌套层次多时难懂结构更清晰

完整示例:计时装饰器

Python
import time
from functools import wraps


class Timer:
    "计时装饰器:记录函数执行时间"

    def __init__(self, func=None, *, precision=3):
        self.func = func
        self.precision = precision
        self.total_time = 0
        self.call_count = 0
        if func:
            wraps(func)(self)

    def __call__(self, *args, **kwargs):
        # 支持 @Timer 和 @Timer(precision=2) 两种用法
        if self.func is None:
            self.func = args[0]
            wraps(self.func)(self)
            return self

        start = time.perf_counter()
        result = self.func(*args, **kwargs)
        elapsed = time.perf_counter() - start

        self.total_time += elapsed
        self.call_count += 1

        print(f"{self.func.__name__} executed in {elapsed:.{self.precision}f}s")
        return result

    def stats(self):
        "返回统计信息"
        avg = self.total_time / self.call_count if self.call_count else 0
        return {
            "calls": self.call_count,
            "total": round(self.total_time, self.precision),
            "average": round(avg, self.precision)
        }


@Timer(precision=4)
def slow_function(n):
    time.sleep(n)
    return n * 2


slow_function(0.1)  # slow_function executed in 0.1001s
slow_function(0.2)  # slow_function executed in 0.2002s
print(slow_function.stats())  # {'calls': 2, 'total': 0.3003, 'average': 0.1502}

要点总结

要点说明
核心方法实现 __call__ 使实例可调用
初始化__init__ 接收被装饰函数或参数
状态管理通过实例属性维护装饰器状态
元信息使用 wraps(func)(self) 保留属性

类装饰器适合需要状态管理、多方法扩展的复杂装饰器场景。

D:\git2\jwdev\articles\PYTHON\进阶\装饰器深入\类装饰器.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 Python 带参数装饰器
下一篇 → Python 装饰器堆叠
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库