在Python 3中检测类中的绑定方法(非实例)

4 投票
3 回答
2501 浏览
提问于 2025-04-17 07:51

假设有一个类叫做 C,里面有一个函数或方法叫 f。我用 inspect.ismethod(obj.f) 来判断 f 是否是绑定的方法,其中 objC 的一个实例。请问有没有办法在类的层面上直接判断(而不需要创建对象)?

使用 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 个回答

0

因为在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了。

0

你可以试试用 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 中是会变化的。

5

在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的实例,在它绑定到类之前。

撰写回答