Python中的类装饰器与函数装饰器的区别与实现原理
字数 532 2025-11-25 20:32:18

Python中的类装饰器与函数装饰器的区别与实现原理

题目描述
类装饰器和函数装饰器都是Python中用于修改或增强函数/类行为的工具,但它们在实现机制、应用场景和内部原理上存在重要差异。这个知识点考察你对装饰器本质的理解,以及如何根据需求选择适当的装饰器类型。

基本概念回顾

  1. 函数装饰器:接收函数作为参数,返回一个新函数的可调用对象
  2. 类装饰器:接收类作为参数,返回修改后的类或新类的可调用对象

函数装饰器的实现原理

def simple_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数: {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

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

# 等价于:say_hello = simple_decorator(say_hello)

类装饰器的两种实现方式

方式一:返回修改后的原类

def add_method(cls):
    """类装饰器:给类添加新方法"""
    def new_method(self):
        return f"这是新增的方法,实例属性: {getattr(self, 'name', '无')}"
    
    cls.get_info = new_method  # 直接修改原类
    return cls  # 返回原类引用

@add_method
class Person:
    def __init__(self, name):
        self.name = name

person = Person("Alice")
print(person.get_info())  # 输出:这是新增的方法,实例属性: Alice

方式二:返回新类(继承方式)

def logged(cls):
    """类装饰器:创建继承原类的新类,添加日志功能"""
    class NewClass(cls):
        def __init__(self, *args, **kwargs):
            print(f"创建 {cls.__name__} 实例")
            super().__init__(*args, **kwargs)
    
    NewClass.__name__ = f"Logged{cls.__name__}"
    return NewClass

@logged
class Calculator:
    def add(self, a, b):
        return a + b

calc = Calculator()  # 输出:创建 Calculator 实例
print(calc.add(2, 3))  # 输出:5
print(type(calc))  # 输出:<class '__main__.LoggedCalculator'>

带参数的类装饰器

def add_attributes(**kwargs):
    """带参数的类装饰器工厂函数"""
    def decorator(cls):
        for attr_name, attr_value in kwargs.items():
            setattr(cls, attr_name, attr_value)
        return cls
    return decorator

@add_attributes(version="1.0", author="Python")
class MyClass:
    pass

print(MyClass.version)  # 输出:1.0
print(MyClass.author)   # 输出:Python

类作为装饰器(可调用类)

class CountInstances:
    """类作为装饰器:统计类实例化次数"""
    def __init__(self, cls):
        self.cls = cls
        self.count = 0
    
    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"创建第 {self.count}{self.cls.__name__} 实例")
        return self.cls(*args, **kwargs)

@CountInstances
class MyClass:
    def __init__(self, name):
        self.name = name

obj1 = MyClass("first")   # 输出:创建第 1 个 MyClass 实例
obj2 = MyClass("second")  # 输出:创建第 2 个 MyClass 实例

关键区别与选择标准

  1. 修改目标不同

    • 函数装饰器:修改函数行为
    • 类装饰器:修改类定义或实例化过程
  2. 执行时机不同

    • 函数装饰器:在函数定义时执行一次
    • 类装饰器:在类定义时执行一次
  3. 适用场景

    • 函数装饰器:日志、缓存、权限检查等函数级别增强
    • 类装饰器:添加类方法、修改类属性、实现单例模式等类级别修改

实际应用示例:单例模式实现

def singleton(cls):
    """类装饰器实现单例模式"""
    instances = {}
    
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    
    return get_instance

@singleton
class DatabaseConnection:
    def __init__(self):
        print("初始化数据库连接")

db1 = DatabaseConnection()  # 输出:初始化数据库连接
db2 = DatabaseConnection()  # 无输出(使用已创建的实例)
print(db1 is db2)  # 输出:True

总结
类装饰器和函数装饰器虽然语法相似,但应用对象和内部机制完全不同。理解它们的区别有助于在适当场景选择正确的工具,类装饰器更适合对类结构进行元编程操作,而函数装饰器更适合增强函数行为。

Python中的类装饰器与函数装饰器的区别与实现原理 题目描述 类装饰器和函数装饰器都是Python中用于修改或增强函数/类行为的工具,但它们在实现机制、应用场景和内部原理上存在重要差异。这个知识点考察你对装饰器本质的理解,以及如何根据需求选择适当的装饰器类型。 基本概念回顾 函数装饰器:接收函数作为参数,返回一个新函数的可调用对象 类装饰器:接收类作为参数,返回修改后的类或新类的可调用对象 函数装饰器的实现原理 类装饰器的两种实现方式 方式一:返回修改后的原类 方式二:返回新类(继承方式) 带参数的类装饰器 类作为装饰器(可调用类) 关键区别与选择标准 修改目标不同 : 函数装饰器:修改函数行为 类装饰器:修改类定义或实例化过程 执行时机不同 : 函数装饰器:在函数定义时执行一次 类装饰器:在类定义时执行一次 适用场景 : 函数装饰器:日志、缓存、权限检查等函数级别增强 类装饰器:添加类方法、修改类属性、实现单例模式等类级别修改 实际应用示例:单例模式实现 总结 类装饰器和函数装饰器虽然语法相似,但应用对象和内部机制完全不同。理解它们的区别有助于在适当场景选择正确的工具,类装饰器更适合对类结构进行元编程操作,而函数装饰器更适合增强函数行为。