如何检测Python类是否调用指定self.foo()方法以校验登记字典完整性
检测类是否调用指定方法的实现方案
完全可以实现,你可以用Python自带的ast(抽象语法树)模块静态解析类方法源码,配合继承关系校验完成检测,因为你已经明确排除了getattr等动态属性访问场景,所有目标调用都以self.foo()形式实现,该方案准确率可以满足需求。
实现逻辑
- 先遍历所有继承自
Human的候选类,按类的MRO(方法解析顺序)查找所有未被子类重写的方法 - 解析每个方法的源码为AST节点,遍历节点查找
self.foo()形式的调用 - 只要在任意未被重写的方法中找到对应调用,就判定该类符合登记要求
示例实现代码
import ast import inspect from typing import Type, Set # 你的业务基类 class Human: def foo(self): ... def has_self_method_call(cls: Type, target_method: str = 'foo') -> bool: """检测类是否存在 self.{target_method}() 调用(含继承的未重写方法)""" # 仅校验Human的子类 if not issubclass(cls, Human): return False seen_methods: Set[str] = set() # 按MRO顺序遍历除Human外的所有父类 human_idx = cls.__mro__.index(Human) for base_cls in cls.__mro__[:human_idx]: for method_name, method in inspect.getmembers(base_cls, inspect.isfunction): # 已存在同名方法说明子类已重写,跳过父类版本 if method_name in seen_methods: continue seen_methods.add(method_name) # 解析方法源码 try: source_code = inspect.getsource(method) ast_tree = ast.parse(source_code) except OSError: # 无法获取源码的内置/扩展方法直接跳过 continue # 查找self.xxx()调用节点 for node in ast.walk(ast_tree): if ( isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute) and isinstance(node.func.value, ast.Name) and node.func.value.id == 'self' and node.func.attr == target_method ): return True return False # 测试用例校验逻辑 def validate_callsfoo_registry(all_human_subclasses: Set[Type], registry: dict): actual_call_classes = set(cls for cls in all_human_subclasses if has_self_method_call(cls)) registered_classes = set(registry.values()) # 校验漏登 missing = actual_call_classes - registered_classes assert not missing, f"漏登类:{[c.__name__ for c in missing]}" # 校验多登 extra = registered_classes - actual_call_classes assert not extra, f"误登类:{[c.__name__ for c in extra]}"
适配说明
该方案自动覆盖你示例中的所有场景:
- 可以识别Anna类中
bar方法的直接调用 - 会排除仅重写
foo但没有调用self.foo的Bob类 - 可以识别Charlie类中
baz方法内分支判断里的调用 - 可以识别继承了Charlie的
baz方法、没有重写的David类
内容的提问来源于stack exchange,提问作者Martin Thoma
相关产品推荐
相关产品推荐

