1

I have two classes:

class A(object): def a(self): pass class B(A): def b(self): pass print dir(A) print dir(B) 

How can I check from which class methods is derived in Python?

For example:

getMethodClass(A.a) == A getMethodClass(B.a) == A getMethodClass(B.b) == B 
3
  • FYI getattr(A, 'a') is just a silly way to write A.a, and type(A) is a Python expression that evaluates to type - you probably want just A. Commented Apr 6, 2014 at 18:26
  • @delnan Read question again I was improve it as you suggest - I make mistake indeed good hint. Commented Apr 6, 2014 at 18:31
  • See also stackoverflow.com/questions/22898037/… which asks how to do the same thing from inside the method, rather than from outside. Commented Sep 9, 2014 at 18:20

1 Answer 1

1

Interesting question. Here is how I'd go about it.

(This works in python2. I haven't tested it in python3, but I won't be surprised if it does not work...)

You can iterate over all the "nominees" using reversed(inspect.getmro(cls)), and returning the first (by fetching the next value of the iterator) which satisfy the condition that it has the relevant attr, and that attr is the same as the method of the relevant cls.

Method identity-comparison is done by comparing the im_func attribute of the unbound method.

import inspect def getMethodClass(cls, attr): return next( basecls for basecls in reversed(inspect.getmro(cls)) if hasattr(basecls, attr) and getattr(basecls, attr).im_func is getattr(cls, attr).im_func ) getMethodClass(A, 'a') => __main__.A getMethodClass(B, 'a') => __main__.A getMethodClass(B, 'b') => __main__.B # an alternative implementation, suggested by @chameleon def getAttributeClass(cls, attrName): # check first if has attribute attr = getattr(cls, attrName) mro = inspect.getmro(cls) # only one class on list if len(mro) == 1: return cls # many class on list for base in reversed(mro[1:]): # check if defined in this base try: baseAttr = getattr(base, attrName) except AttributeError: continue else: if baseAttr.im_func is attr.im_func: return base # define in top class return cls 

The function can also have the signature you suggest:

def getMethodClass(unbound_method): cls = unbound_method.im_class attr = unbound_method.__name__ # rest of implementation is the same as before... getMethodClass(B.a) => __main__.A 
Sign up to request clarification or add additional context in comments.

5 Comments

Looks good but I think better is to use inspect.getmro(cls) and not use reverse whatever it should work. What do you think? You can also skip first on mro() since first is class tested.
I guess you're right about using inspect.getmro. I'm not sure how you'd expect it to work without reverseing -- it would always return cls. Also, skipping the first on mro() would make the code more complex, with no apparent benefit -- you'd still need to return cls in some cases, so why not include it in the list you iterate over?
Why exclude first since first always pass condition getattr(cls, attr).im_func == getattr(cls, attr).im_func you can set result to cls and try to replace it with first hit result = cls for x in mro(): if x != cls and ...: result = x - do you understand me?
It will lead to such construct x = something, search in loop for replace for x if no replace x will be not changed. BTW for me next() is not know since very rare I will train it.
Yes, your alternative implementation would work just as well.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.