My question is somewhat similar to this one; it concerns object methods rather than module contents. I want to know if I can use the inspect
module to get the methods defined only in the class I'm asking about, and not its parent(s).
I need this because my child class defines 'macro' methods, which accesses the parent's methods at a higher level of abstraction, and I don't want the user to have to worry about the lower-level methods defined all the way up the inheritance tree.
Here is a simplified example:
class Foo(object):
def __init__(self): pass
def f1(self): return 3
def f2(self): return 1
class Bar(Foo):
def __init__(self): Foo.__init__(self)
def g1(self): return self.f1() + self.f2()
def g2(self): return self.f1() - self.f2()
import inspect
inspect.getmembers(Bar, inspect.ismethod)
Output:
[('__init__', <unbound method Bar.__init__>),
('f1', <unbound method Bar.f1>),
('f2', <unbound method Bar.f2>),
('g1', <unbound method Bar.g1>),
('g2', <unbound method Bar.g2>)]
The user need not know or care about the existence of the f
s since she's only ever going to be interested in the g
s. (Of course, this output makes sense in the vast majority of contexts, since all these methods will be bound to the object when it is instantiated.) For a long inheritance tree, the returned list can get very long and full of things that aren't relevant to the user.
How can I get it to leave f1
and f2
off this list? Is there an equivalent to the __module__
attribute for the methods defined in classes? Better still, is it possible to do the same thing with instance methods?
Methods have an
im_class
attribute, that points to the class in question. You can use that filter on functions that are members of the class:This gives you:
Of course, you can just bypass
getmembers
altogether then:gives:
This applies to bound or unbound methods, they have same
.__func__
(orim_func
, the old name) attribute. The difference between bound and unbound is the value of the.__self__
attribute (None when unbound).These "secret" attributes are all documented in the Python Data Model.
Hopefully someone will come along with a better solution, but what about:
Of course, in a real situation, you might need to walk through
Bar.__bases__
to actually get rid of everything you don't want.e.g.: