打卡Day29
类修改器的逻辑:接收一个类,返回一个修改后的类。例如:
- 添加新的方法或属性(如示例中的 log 方法)。
- 修改原有方法(如替换 init 方法,添加日志)。
- 甚至可以返回一个全新的类(继承或组合原类)。
# 定义类装饰器:为类添加日志功能
def class_logger(cls): #这个装饰器接受一个类 cls 作为参数。# 保存原始的 __init__ 方法original_init = cls.__init__ #保存了原始的 __init__ 方法(即类的构造函数),以便在新的构造函数中调用它。def new_init(self, *args, **kwargs): #定义新的构造函数 new_init# 新增实例化日志print(f"[LOG] 实例化对象: {cls.__name__}")original_init(self, *args, **kwargs) # 调用原始构造方法# 将类的 __init__ 方法替换为新方法cls.__init__ = new_init #将新的构造函数 new_init 赋值给类的 __init__ 属性,这样当实例化类时,会自动调用新的构造函数。# 为类添加一个日志方法(示例)def log_message(self, message): #定义了一个名为 log_message 的方法,该方法接受一个消息 message 作为参数。print(f"[LOG] {message}") #打印一条日志消息,包含传递的消息 message。cls.log = log_message # 将方法绑定到类,这是一种将外部函数添加为类的属性的方法return cls# 定义简单打印类,应用装饰器
# 同样是语法糖的写法
@class_logger
class SimplePrinter:def __init__(self, name):self.name = name # 构造方法:初始化名称def print_text(self, text):"""简单打印方法"""print(f"{self.name}: {text}")# 使用示例
printer = SimplePrinter("Alice") # 实例化时触发装饰器的日志
printer.print_text("Hello, World!") # 调用普通方法
printer.log("这是装饰器添加的日志方法") # 调用装饰器新增的方法
注意到其中的cls.log = log_message 这行代码,他把外部的函数赋值给了类的新定义的属性,这里介绍这种写法
总结流程:
定义类装饰器:为类添加日志功能
保存了原始的 init 方法(即类的构造函数),以便在新的构造函数中调用它。
定义新的构造函数
新增实例化日志
将类的 init 方法替换为新方法:将新的构造函数 new_init 赋值给类的 init 属性,这样当实例化类时,会自动调用新的构造函数。
实际上,定义类的方法,有2类写法
- 在类定义内部直接写方法,这是静态方法,一般定义类都这么完成。
- 在类定义外部定义方法,然后把方法赋值给类的属性—这是一种动态方法,常在装饰器中使用,可以再外部修改类的方法。
本质区别
特性 | 类内部定义方法 | 外部赋值定义方法 |
---|---|---|
语法 | 在 class 块内使用 def | 定义函数后赋值给类属性(如 cls.fn = fn ) |
作用域 | 方法可以直接访问类的其他私有成员 | 需要通过 self 或类名显式访问 |
动态性 | 类定义后方法固定 | 可以在运行时动态添加/修改方法 |
常见场景 | 常规类定义 | 装饰器、元类、动态编程 |
两种方式的本质都是将函数对象绑定到类的属性上,只是语法和应用场景不同。装饰器中常用外部赋值,是为了在不修改原类代码的情况下增强类的功能。