如何在Python单继承层级中定位方法的定义类?
嘿,这个问题我太熟了!刚好之前做元编程相关需求时折腾过类似场景,咱们一步步来拆解解决它。
首先明确你的核心需求:在单继承的类层级里,不用调用方法的前提下,找到某个方法实际被定义的类——比如你举的例子里,E().f()实际调用的是D类里的f,你想通过get_defining_class(E, 'f')直接拿到D。
先给你吃个定心丸:你提到的遍历__mro__搜索的思路完全可行,而且这正是Python本身查找方法的逻辑,精准度拉满!
具体实现思路
Python的每个类都有__mro__属性,它是一个元组,按照「从最具体的子类到最抽象的父类」的顺序排列了整个继承链(比如你的例子里E.__mro__就是(E, D, C, object))。我们要做的就是顺着这个顺序找第一个自己定义了目标方法的类——这里必须强调「自己定义」,因为如果只是用hasattr检查,会把父类继承来的方法也当成当前类的,导致拿到错误的结果。而'f' in cls.__dict__可以准确判断方法是不是当前类自己定义的(继承来的属性不会出现在子类的__dict__里,除非被覆盖)。
代码示例
先补全你原代码里的小问题(实例方法需要加self参数,不然实例调用会报错):
class C: def f(self): pass class D(C): def f(self): pass class E(D): pass
然后实现我们的get_defining_class函数:
def get_defining_class(target_cls, method_name): # 按MRO顺序遍历继承链 for cls in target_cls.__mro__: # 检查当前类是否自己定义了该方法 if method_name in cls.__dict__: return cls # 遍历完没找到的话返回None(也可以根据需求抛异常) return None
现在来验证效果,完全符合你的预期:
assert get_defining_class(E, 'f') == D assert get_defining_class(D, 'f') == D assert get_defining_class(C, 'f') == C assert get_defining_class(E, 'g') is None # 不存在的方法返回None
额外小技巧:如果拿到的是方法对象而不是方法名
如果你手里已经有一个方法对象(比如E().f),也可以用这个函数来查找,只需要先拿到实例的类和方法名:
e = E() # 从实例方法对象中提取类和方法名 assert get_defining_class(e.__class__, e.f.__name__) == D
常见疑问解答
你之前问「遍历E.__mro__找'f'是否可行?」——这个方向完全对,只是要注意不能只检查hasattr,必须用__dict__来确认是当前类自己定义的方法,这样才能精准定位到第一个定义该方法的类,和Python实际调用方法时的查找逻辑完全一致。
备注:内容来源于stack exchange,提问作者user200783

