问题
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?
回答1:
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:
inspect.getmembers(Bar,
lambda m: inspect.ismethod(m) and m.__func__ in m.im_class.__dict__.values())
This gives you:
[
('__init__', <unbound method Bar.__init__>),
('f1', <unbound method Bar.f1>),
('f2', <unbound method Bar.f2>)
]
Of course, you can just bypass getmembers
altogether then:
[m for m in Bar.__dict__.values() if inspect.isfunction(m)]
gives:
[<function __init__ at 0x100a28de8>, <function g1 at 0x100a28e60>, <function g2 at 0x100a28ed8>]
This applies to bound or unbound methods, they have same .__func__
(or im_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.
回答2:
Hopefully someone will come along with a better solution, but what about:
foo_members = inspect.getmembers(Foo,inspect.ismethod)
bar_members = inspect.getmembers(Bar,inspect.ismethod)
set(bar_members) - set(foo_members)
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.:
set(bar_members) - set(sum([inspect.getmembers(base,inspect.ismethod) for base in Bar.__bases__],[]))
来源:https://stackoverflow.com/questions/11934212/python-how-can-i-query-the-class-in-which-a-method-is-defined