Obrigado Sr2222 por apontar que eu estava perdendo o ponto ...
Aqui está a abordagem corrigida, que é igual à de Alex, mas não exige a importação de nada. No entanto, não acho que seja uma melhoria, a menos que haja uma enorme hierarquia de classes herdadas, já que essa abordagem para assim que a classe definidora é encontrada, em vez de retornar toda a herança como o getmro
faz. Como disse, este é um cenário muito improvável.
def get_class_that_defined_method(method):
method_name = method.__name__
if method.__self__:
classes = [method.__self__.__class__]
else:
classes = [method.im_class]
while classes:
c = classes.pop()
if method_name in c.__dict__:
return c
else:
classes = list(c.__bases__) + classes
return None
E o exemplo:
>>> class A(object):
... def test(self): pass
>>> class B(A): pass
>>> class C(B): pass
>>> class D(A):
... def test(self): print 1
>>> class E(D,C): pass
>>> get_class_that_defined_method(A().test)
<class '__main__.A'>
>>> get_class_that_defined_method(A.test)
<class '__main__.A'>
>>> get_class_that_defined_method(B.test)
<class '__main__.A'>
>>> get_class_that_defined_method(C.test)
<class '__main__.A'>
>>> get_class_that_defined_method(D.test)
<class '__main__.D'>
>>> get_class_that_defined_method(E().test)
<class '__main__.D'>
>>> get_class_that_defined_method(E.test)
<class '__main__.D'>
>>> E().test()
1
A solução de Alex retorna os mesmos resultados. Contanto que a abordagem de Alex possa ser usada, eu a usaria em vez desta.