【问题标题】:Python - How can I query the class in which a method is defined?Python - 如何查询定义方法的类?
【发布时间】:2012-08-13 12:22:22
【问题描述】:

我的问题有点类似于this one;它涉及对象方法而不是模块内容。我想知道我是否可以使用inspect 模块来获取只在我询问的类中定义的方法,而不是它的父类。

我需要这个,因为我的子类定义了“宏”方法,它以更高的抽象级别访问父级的方法,我不希望用户担心一路定义的低级方法继承树。

这是一个简化的例子:

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)

输出:

[('__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>)]

用户不需要知道或关心fs 的存在,因为她只会对gs 感兴趣。 (当然,这个输出在绝大多数情况下都是有意义的,因为所有这些方法都将在实例化时绑定到对象。)对于长继承树,返回的列表可能会变得很长并且充满了'与用户无关。

我怎样才能让它从这个列表中删除f1f2?类中定义的方法是否有与__module__ 属性等效的属性?更好的是,是否可以用 instance 方法做同样的事情?

【问题讨论】:

  • 在绑定方法(Bar 的实例)上请求 im_class 不起作用。它也不适用于未绑定的方法。
  • object.hasOwnPro… 等一下,这是不对的。 (抱歉,我简直不敢相信 JavaScript 比 Python 更容易做的事情。)

标签: python methods introspection inspect


【解决方案1】:

方法有一个im_class 属性,它指向有问题的类。您可以对该类成员的函数使用该过滤器:

inspect.getmembers(Bar,
    lambda m: inspect.ismethod(m) and m.__func__ in m.im_class.__dict__.values())

这给了你:

[
    ('__init__', <unbound method Bar.__init__>),
    ('f1', <unbound method Bar.f1>), 
    ('f2', <unbound method Bar.f2>)
]

当然,你可以完全绕过getmembers

[m for m in Bar.__dict__.values() if inspect.isfunction(m)]

给予:

[<function __init__ at 0x100a28de8>, <function g1 at 0x100a28e60>, <function g2 at 0x100a28ed8>]

这适用于绑定或未绑定的方法,它们具有相同的.__func__(或im_func,旧名称)属性。绑定和未绑定的区别在于.__self__ 属性的值(未绑定时为无)。

这些“秘密”属性都记录在Python Data Model中。

【讨论】:

  • 哇...这看起来有点像黑魔法。你在哪里学的这些东西? (+1)
  • @mgilson:添加了一个指针;另外,dir() 是你的朋友,一如既往。不过,必须说,在我职业生涯的不同阶段曾与一些最伟大的 Python 开发人员一起工作,这有它的优势。 :-)
  • 啊......我从来没有太多需要深入挖掘 python 的内部工作原理,它具有惊人的内省能力(我的幼稚回答可能很明显)。我经常对您回答这些有趣问题的能力感到惊讶,就好像您已经记住了整个数据模型一样。
  • @MartijnPieters 我对__dict__ 之类的东西以及它们的实际工作方式不是很熟悉。当在类对象或实例对象上调用时,您能解释__dict__dir()inspect.getmembers() 之间的区别吗?他们似乎都给出了不同的输出
  • @poorsod: __dict__ 是类的基本命名空间; dir()inspect.getmembers() 都将其与其他信息一起使用来构建更大的结构(包括向下递归 .__bases__ 类层次结构。
【解决方案2】:

希望有人会提出更好的解决方案,但是呢:

foo_members = inspect.getmembers(Foo,inspect.ismethod)
bar_members = inspect.getmembers(Bar,inspect.ismethod)

set(bar_members) - set(foo_members)

当然,在真实情况下,您可能需要遍历Bar.__bases__ 才能真正摆脱您不想要的一切。

例如:

set(bar_members) - set(sum([inspect.getmembers(base,inspect.ismethod) for base in Bar.__bases__],[]))

【讨论】:

  • 或者对于更通用的解决方案,使用 Bar.__bases__ 而不是硬编码的 Foo。
  • @Alfe -- 将__mro__ 更改为__bases__ 并添加了一个示例。
猜你喜欢
  • 1970-01-01
  • 2020-04-20
  • 2014-11-03
  • 2015-12-29
  • 2017-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-04
相关资源
最近更新 更多