在Python 3中检测类中的绑定方法(非实例)
假设有一个类叫做 C
,里面有一个函数或方法叫 f
。我用 inspect.ismethod(obj.f)
来判断 f
是否是绑定的方法,其中 obj
是 C
的一个实例。请问有没有办法在类的层面上直接判断(而不需要创建对象)?
使用 inspect.ismethod
这样做是行不通的:
class C(object):
@staticmethod
def st(x):
pass
def me(self):
pass
obj = C()
在 Python 3 中,这样的结果是:
>>> inspect.ismethod(C.st)
False
>>> inspect.ismethod(C.me)
False
>>> inspect.ismethod(obj.st)
False
>>> inspect.ismethod(obj.me)
True
我想我需要检查这个函数/方法是否是类的成员,并且不是静态方法,但我没有找到简单的方法来做到这一点。我猜可以使用 classify_class_attrs
来实现,具体可以参考这里
如何确定 Python 类的每个属性和方法是在哪里定义的?
不过我希望能有一种更直接的方法。
3 个回答
因为在Python 2.7中,inspect.ismethod对绑定方法和未绑定方法都返回True(也就是说,它有点问题),所以我使用了:
def is_bound_method(obj):
return hasattr(obj, '__self__') and obj.__self__ is not None
这个方法也适用于用C语言实现的类的方法,比如int:
>>> a = 1
>>> is_bound_method(a.__add__)
True
>>> is_bound_method(int.__add__)
False
不过在这种情况下,这个方法不是特别有用,因为inspect.getargspec对用C语言实现的函数不适用。
在Python 3中,is_bound_method的功能没有变化,但inspect.ismethod能够正确区分绑定方法和未绑定方法,所以在Python 3中就不需要使用is_bound_method了。
你可以试试用 inspect.isroutine(...)
吗?我用你的类 C
运行了一下,得到了:
>>> inspect.isroutine(C.st)
True
>>> inspect.isroutine(C.me)
True
>>> inspect.isroutine(obj.st)
True
>>> inspect.isroutine(obj.me)
True
把 inspect.isroutine(...)
的结果和 inspect.ismethod(...)
的结果结合起来,可能能帮助你推断出你需要知道的东西。
编辑: dm03514 的回答建议你也可以试试 inspect.isfunction()
:
>>> inspect.isfunction(obj.me)
False
>>> inspect.isfunction(obj.st)
True
>>> inspect.isfunction(C.st)
True
>>> inspect.isfunction(C.me)
False
不过正如 Hernan 指出的那样,inspect.isfunction(...)
的结果在 Python 3 中是会变化的。
在Python 3中,没有所谓的“未绑定方法”,所以你也无法检测到它们。你看到的都是普通函数。最多你能看到它们是否有一个带点的“合格名称”,这表示它们是嵌套的,并且它们的第一个参数名是self
:
if '.' in method.__qualname__ and inspect.getargspec(method).args[0] == 'self':
# regular method. *Probably*
当然,这种方法对于静态方法和那些恰好把self
作为第一个参数的嵌套函数来说完全不管用,还有那些不把self
作为第一个参数的普通方法(这可是违反常规的哦)。
对于静态方法和类方法,你需要查看类字典:
>>> isinstance(vars(C)['st'], staticmethod)
True
这是因为C.__dict__['st']
实际上就是staticmethod
的实例,在它绑定到类之前。