如何仅包装类中方法的最外层(最新)实现?
如何只包装类中
run()方法的最外层实现? 这个问题确实很典型——当用元类统一包装方法时,继承链中的嵌套调用很容易破坏我们原本的状态管理逻辑。我有个很实用的解决方案,既能自动包装最外层的run()实现,又不需要对派生类做任何特殊处理:
核心思路
我们需要实现两个关键点:
- 避免对同一个
run()方法进行重复包装 - 只有最外层的
run()调用才会修改实例状态,内部通过super()调用的基类run()不触发状态变更
完整实现代码
from functools import wraps from types import FunctionType from somewhere import State def wrapper(method): @wraps(method) def wrapped(_instance, *args, **kwargs): # 如果实例已经处于Running状态,说明是内部嵌套调用,直接执行原方法 if _instance.state == State.Running: return method(_instance, *args, **kwargs) # 最外层调用:设置状态为Running _instance.state = State.Running try: # 执行原方法(包含派生类中调用super的逻辑) return method(_instance, *args, **kwargs) finally: # 无论方法是否抛出异常,最终都将状态设为Finished _instance.state = State.Finished # 给包装后的方法添加标记,防止元类重复包装 wrapped._is_wrapped = True return wrapped class MetaClass(type): def __new__(meta, classname, bases, classDict): newClassDict = {} for attributeName, attribute in classDict.items(): # 只对当前类原生定义的、未被包装过的run()方法进行包装 if (attributeName == 'run' and isinstance(attribute, FunctionType) and not getattr(attribute, '_is_wrapped', False)): attribute = wrapper(attribute) newClassDict[attributeName] = attribute return type.__new__(meta, classname, bases, newClassDict) class AmazingClass(metaclass=MetaClass): def __init__(self): self.state = State.Idle def run(self, *args, **kwargs): print(f"AmazingClass.run: 当前状态 {self.state}") # do_something() class EvenMoreAmazingClass(AmazingClass): def run(self, *args, **kwargs): print(f"EvenMoreAmazingClass.run: 当前状态 {self.state}") super().run(*args, **kwargs) print(f"EvenMoreAmazingClass.run: super调用后状态 {self.state}") # do_something_else()
效果验证
运行以下测试代码:
obj = EvenMoreAmazingClass() print(f"初始化后状态: {obj.state}") obj.run() print(f"run执行完成后状态: {obj.state}")
输出结果:
初始化后状态: State.Idle EvenMoreAmazingClass.run: 当前状态 State.Running AmazingClass.run: 当前状态 State.Running EvenMoreAmazingClass.run: super调用后状态 State.Running run执行完成后状态: State.Finished
可以看到:
- 最外层的
EvenMoreAmazingClass.run()启动时将状态设为Running - 调用
super().run()时,因为状态已经是Running,基类的run()不会修改状态 - 只有当最外层的
run()完全执行完毕(包括后续的do_something_else()),状态才会被设为Finished
为什么这个方案有效?
- 状态检查:通过判断实例当前的
state,避免嵌套调用时重复修改状态 - 防重复包装标记:
_is_wrapped属性确保每个原生run()方法只会被包装一次,不会因为继承或多层嵌套包装导致逻辑混乱 - 异常安全:使用
try-finally保证即使run()抛出异常,状态也能正确恢复为Finished
内容的提问来源于stack exchange,提问作者Lord SIGSEG V
相关产品推荐
相关产品推荐

