Day 29 训练
Day 29 训练
- Day 29:Python 类装饰器的奥秘与实践
- 一、类装饰器:函数装饰器的升级版
- 二、类装饰器 VS 函数装饰器:核心区别
- 三、实战:为类添加日志功能
- 四、类方法定义的两种风格
- 1. 类内部定义方法(常规方式)
- 2. 外部赋值定义方法(动态方式)
- 五、动态修改已定义的类
Day 29:Python 类装饰器的奥秘与实践
在编程的世界里,装饰器是一种强大的工具,它允许我们在不修改原函数或类代码的情况下,增强其功能。今天,我们深入探索类装饰器的魔力,解锁更高级的封装技巧。
一、类装饰器:函数装饰器的升级版
函数装饰器我们已经比较熟悉了,它接收一个函数,返回一个修改后的函数,用于在调用前后添加额外功能(如日志记录、权限验证等)。而类装饰器则更进一步:它接收一个类,返回一个修改后的类。这个强大的特性使我们能够在不触碰原始类代码的前提下,为类添加新的方法、修改现有方法甚至替换整个类。
二、类装饰器 VS 函数装饰器:核心区别
特性 | 函数装饰器 | 类装饰器 |
---|---|---|
作用对象 | 函数(Function) | 类(Class) |
传入参数 | 接收函数作为参数(def decorator(func):) | 接收类作为参数(def decorator(cls):) |
返回值 | 返回包装后的函数(通常是闭包) | 返回修改后的类(可以是原类或新类) |
常见用途 | 修改函数行为(如日志、计时、权限验证) | 修改类的结构(如添加属性、方法、修改初始化逻辑) |
核心逻辑 | 用闭包包裹函数,在不修改函数代码的前提下扩展功能 | 直接修改类的定义(如添加/替换方法、属性) |
三、实战:为类添加日志功能
让我们通过一个简单的例子来理解类装饰器的实际应用。我们定义一个类装饰器 class_logger
,用于为类添加日志功能。
def class_logger(cls):# 保存原始的 __init__ 方法original_init = cls.__init__def new_init(self, *args, **kwargs):# 新增实例化日志print(f"[LOG] 实例化对象: {cls.__name__}")original_init(self, *args, **kwargs) # 调用原始构造方法# 将类的 __init__ 方法替换为新方法cls.__init__ = new_init# 为类添加一个日志方法(示例)def log_message(self, message):print(f"[LOG] {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("这是装饰器添加的日志方法") # 调用装饰器新增的方法
输出结果:
[LOG] 实例化对象: SimplePrinter
Alice: Hello, World!
[LOG] 这是装饰器添加的日志方法
在这个例子中,class_logger
装饰器为 SimplePrinter
类添加了两个功能:
- 在实例化对象时记录日志。
- 为类添加了一个新的
log
方法,用于记录自定义消息。
四、类方法定义的两种风格
在 Python 中,定义类的方法有两种主要方式:
1. 类内部定义方法(常规方式)
class MyClass:def method(self):print("这是类内部定义的方法")
这种方式简单直观,是定义类方法的常规方式。方法可以直接访问类的其他成员,包括私有成员。
2. 外部赋值定义方法(动态方式)
def external_method(self):print("这是外部定义的方法")class MyClass:passMyClass.external_method = external_method # 动态添加方法
这种方式允许我们在类定义完成后再动态添加方法,常用于装饰器、元类和动态编程场景。需要注意的是,外部定义的方法需要通过 self
或类名显式访问类的其他成员。
五、动态修改已定义的类
装饰器的本质是语法糖。对于类装饰器而言,@decorator
语法实际上是 MyClass = decorator(MyClass)
的简写。这意味着即使类已经定义完成,我们仍然可以通过手动调用装饰器函数来修改它。
class ExistingClass:def __init__(self, value):self.value = value# 手动应用装饰器修改已定义的类
ExistingClass = class_logger(ExistingClass)obj = ExistingClass("Test") # 触发装饰器添加的日志功能
浙大疏锦行