类装饰器
本课属于 Coddy Python 学习旅程的“面向对象编程”单元。第 40 课,共 64 课。
类装饰器可以通过用另一个函数包装类来修改或增强类。它们的工作方式与函数装饰器类似,但应用于整个类。
这是一个没有装饰的简单类:
class Person:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, my name is {self.name}"创建一个类装饰器,用来添加一个新方法:
def add_farewell(cls):
def farewell(self):
return f"Goodbye from {self.name}"
cls.farewell = farewell # 将方法添加到类中
return cls使用 @ 将装饰器应用于类:
@add_farewell
class EnhancedPerson:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, my name is {self.name}"现在这个类既有原始方法,也有新增的方法:
person = EnhancedPerson("Alice")
print(person.greet()) # 你好,我叫 Alice
print(person.farewell()) # Alice 向你道别你也可以包装现有方法:保存原始方法,这样就可以在包装器中继续调用它。如果你想在类已有的方法周围添加行为(例如跟踪或日志记录),这会很有用:
def add_tracking(cls):
original_greet = cls.greet # 保存原来的方法
def tracked_greet(self):
print(f"greet was called") # 先执行额外操作
return original_greet(self) # 调用原来的方法
cls.greet = tracked_greet # 替换类中的方法
return cls
@add_tracking
class TrackedPerson:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, my name is {self.name}"现在调用 greet 时,包装函数会先运行,然后再调用原始函数:
person = TrackedPerson("Alice")
print(person.greet())
# 调用了 greet
# 你好,我叫 Alice包装现有方法的关键步骤如下:
1. 保存原始方法:original = cls.method
2. 定义一个调用 original(self) 并添加其他逻辑的新函数。
3. 将新函数重新赋给类:cls.method = new_function
4. 返回修改后的类。
要点:类装饰器以类为输入,对其进行修改或增强,然后返回修改后的类。它们可以添加方法、修改属性,或包装现有功能。在类定义上方使用 @decorator_name 来应用类装饰器。这样无需继承,也能以简洁的方式扩展类的功能。
挑战
中等在这个挑战中,你将实现一个类装饰器,为方法添加调用跟踪功能。
decorator.py:实现类装饰器add_countercalculator.py:包含将使用你的装饰器的类
driver.py 文件中包含大量测试场景,用于验证你的实现是否适用于各种用例、继承模式和边界情况。你不需要修改这个文件,但查看它有助于你了解预期行为。
亲手试试
from calculator import Calculator
# 综合测试用例处理程序
test_case = input()
if test_case == "basic_functionality":
calc = Calculator()
print(calc.add(5, 3)) # 应输出 8
print(calc.add(2, 7)) # 应输出 9
print(calc.subtract(10, 4)) # 应输出 6
print(calc.call_counts) # 应输出 {'add': 2, 'subtract': 1}
elif test_case == "multiple_instances":
calc1 = Calculator()
calc2 = Calculator()
print(calc1.add(5, 3)) # 应输出 8
print(calc2.add(2, 7)) # 应输出 9
print(calc1.subtract(10, 4)) # 应输出 6
# 两个实例应共享同一个 call_counts
print(calc1.call_counts) # 应输出 {'add': 2, 'subtract': 1}
print(calc2.call_counts) # 应输出 {'add': 2, 'subtract': 1}
print(calc1.call_counts is calc2.call_counts) # 应输出 True
elif test_case == "method_call_order":
calc = Calculator()
print(calc.add(1, 2)) # 应输出 3
print(calc.subtract(5, 2)) # 应输出 3
print(calc.add(10, 20)) # 应输出 30
print(calc.add(7, 3)) # 应输出 10
print(calc.call_counts) # 应输出 {'add': 3, 'subtract': 1}
elif test_case == "large_values":
calc = Calculator()
print(calc.add(1000000, 2000000)) # 应输出 3000000
print(calc.subtract(5000000, 2000000)) # 应输出 3000000
print(calc.call_counts) # 应输出 {'add': 1, 'subtract': 1}
elif test_case == "negative_values":
calc = Calculator()
print(calc.add(-5, -3)) # 应输出 -8
print(calc.subtract(-10, -4)) # 应输出 -6
print(calc.call_counts) # 应输出 {'add': 1, 'subtract': 1}
elif test_case == "float_values":
calc = Calculator()
print(calc.add(5.5, 3.2)) # 应输出 8.7
print(calc.subtract(10.5, 4.2)) # 应输出 6.3
print(calc.call_counts) # 应输出 {'add': 1, 'subtract': 1}
elif test_case == "zero_values":
calc = Calculator()
print(calc.add(0, 0)) # 应输出 0
print(calc.subtract(0, 0)) # 应输出 0
print(calc.call_counts) # 应输出 {'add': 1, 'subtract': 1}
elif test_case == "counter_reset":
calc = Calculator()
print(calc.add(5, 3)) # 应输出 8
print(calc.call_counts) # 应输出 {'add': 1, 'subtract': 0}
# 重置计数器
calc.call_counts = {"add": 0, "subtract": 0}
print(calc.add(2, 7)) # 应输出 9
print(calc.call_counts) # 应输出 {'add': 0, 'subtract': 0}
elif test_case == "counter_manipulation":
calc = Calculator()
print(calc.add(5, 3)) # 应输出 8
print(calc.call_counts) # 应输出 {'add': 1, 'subtract': 0}
# 直接修改计数器
calc.call_counts["add"] = 100
print(calc.add(2, 7)) # 应输出 9
print(calc.call_counts) # 应输出 {'add': 101, 'subtract': 0}
elif test_case == "performance_test":
calc = Calculator()
# 执行 1000 次 add 操作
for i in range(1000):
calc.add(i, i+1)
# 执行 500 次 subtract 操作
for i in range(500):
calc.subtract(i+10, i)
print(calc.call_counts) # 应输出 {'add': 1000, 'subtract': 500}这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Python 在线编译器