Python - How can I query the class in which a method is defined?

[亡魂溺海] 提交于 2019-12-11 03:06:06

问题


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 fs since she's only ever going to be interested in the gs. (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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!