如何实现按调用顺序执行方法时排除指定父类的方法?
实现带父类排除功能的方法调用重放
现有场景
追踪已调用方法的装饰器
我们有一个装饰器,用来记录类实例中被调用过的方法:
def called_methods(func): def inner(self): func(self) self.called.append(func) return inner
三个父类定义
每个类包含两个方法,调用时会输出唯一标识语句:
class ClassOne: def __init__(self): self.called = list() @called_methods def method_one_a(self): print("method one, a") @called_methods def method_one_b(self): print("method one, b") class ClassTwo: def __init__(self): self.called = list() @called_methods def method_two_a(self): print("method two, a") @called_methods def method_two_b(self): print("method two, b") class ClassThree: def __init__(self): self.called = list() @called_methods def method_three_a(self): print("method three, a") @called_methods def method_three_b(self): print("method three, b")
主类实现
主类继承了上述三个父类,提供了按调用顺序重放所有已调用方法的功能:
class MainClass(ClassOne, ClassTwo, ClassThree): def call_functions_in_order(self): for function in self.called: function(self)
示例用法
按任意顺序调用部分方法:
test = MainClass() test.method_one_a() test.method_two_b() test.method_one_b() test.method_three_a() test.method_two_a() test.method_three_b()
执行后输出:
method one, a method two, b method one, b method three, a method two, a method three, b
调用test.call_functions_in_order()会得到完全相同的输出。
需求目标
给call_functions_in_order方法添加exclude参数,指定排除某个父类的所有方法不被执行。例如调用test.call_functions_in_order(exclude='ClassOne')时,输出应为:
method two, b method three, a method two, a method three, b
可行解决方案
要实现这个功能,核心是给每个记录的方法标记所属类,然后在重放时过滤掉被排除的类的方法,具体步骤如下:
1. 修改装饰器,记录方法所属类
原装饰器只存储了方法对象,我们需要额外记录该方法定义的类。可以通过方法的__qualname__属性获取类名,然后把方法和类名一起存入self.called列表:
def called_methods(func): def inner(self): func(self) # 拆分限定名得到类名,比如"ClassOne.method_one_a"拆分后取第一个元素 class_name = func.__qualname__.split('.')[0] # 存储方法对象和对应的类名 self.called.append((func, class_name)) return inner
2. 修改主类方法,添加排除逻辑
更新call_functions_in_order方法,接收exclude参数,遍历记录时跳过属于排除类的方法:
class MainClass(ClassOne, ClassTwo, ClassThree): def call_functions_in_order(self, exclude=None): for function, class_name in self.called: # 如果没有排除类,或者当前方法不属于排除类,则执行 if exclude is None or class_name != exclude: function(self)
验证效果
用之前的示例代码测试:
test = MainClass() test.method_one_a() test.method_two_b() test.method_one_b() test.method_three_a() test.method_two_a() test.method_three_b() # 调用带排除参数的方法 test.call_functions_in_order(exclude='ClassOne')
输出结果完全符合需求:
method two, b method three, a method two, a method three, b
扩展说明
- 如果需要支持排除多个类,可以把
exclude参数改为接收列表,比如exclude=['ClassOne', 'ClassTwo'],然后判断条件改为class_name not in exclude即可。 - 也可以通过
func.__module__或其他属性来标识类,但__qualname__是最直接获取方法所属类的方式,不受实例继承的干扰。
内容的提问来源于stack exchange,提问作者DHJ
相关产品推荐
相关产品推荐

