如何测试一个对象是一个函数还是一个未绑定的方法?

时间:2014-08-01 15:07:18

标签: python introspection

def is_unbound_method(func):
    pass

def foo(): pass

class MyClass(object):
    def bar(self): pass

我可以在is_unbound_method的身体中放置什么

is_unbound_method(foo) == False
is_unbound_method(MyClass().bar) == False
is_unbound_method(MyClass.bar) == True

...

3 个答案:

答案 0 :(得分:8)

未绑定的方法将__self__设置为None

def is_unbound_method(func):
    return getattr(func, '__self__', 'sentinel') is None

演示:

>>> foo.__self__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute '__self__'
>>> is_unbound_method(foo)
False
>>> MyClass.bar.__self__
>>> is_unbound_method(MyClass.bar)
True
>>> MyClass().bar.__self__
<__main__.MyClass object at 0x106c64a50>
>>> is_unbound_method(MyClass().bar)
False

该属性也可用.im_self,但__self__是向前兼容的。

请注意,在Python 3中,未绑定的方法已经消失;访问MyClass.bar返回函数对象。因此,上述函数将始终返回False

请参阅用户定义的方法部分中的Datamodel documentation

  

特殊只读属性:im_self是类实例对象,im_func是函数对象

     

[...]

     

在版本2.6中更改:对于Python 3向前兼容性,im_func也可用作__func__im_self可用作__self__

     

[...]

     

通过从类中检索用户定义的函数对象来创建用户定义的方法对象时,其im_self属性为None,并且方法对象被称为未绑定。

答案 1 :(得分:0)

这就是我提出的......根据正确答案中的评论,仅对2.x有效

def is_unbound_method(func):
    """Test if ``func`` is an unbound method.

    >>> def f(): pass
    >>> class MyClass(object):
    ...     def f(self): pass
    >>> is_unbound_method(f)
    False
    >>> is_unbound_method(MyClass().f)
    False
    >>> is_unbound_method(MyClass.f)
    True

    """
    return getattr(func, 'im_self', False) is None

答案 2 :(得分:0)

在Python 3中,没有可靠的方法可以仅通过函数对象来确定(因为类中定义的任何函数都与其他函数一样)。

也许次优的方法是检查签名并检查self作为第一个参数:

import inspect


def is_unbound_method(obj):
    signature = inspect.signature(obj)
    if not signature.parameters:
        return False
    return next(iter(signature.parameters), None) == "self"

但是,当然,这取决于第一个参数被命名为self在其他函数上 not 而不是使用self作为第一个参数),这只是一个约定。

如果您已经知道对象是在类中定义的,那么更好的方法可能是检查它是不是classmethodstaticmethod的可调用对象: / p>

import inspect


def is_unbound_method_from(cls, obj):
    return bool(
        callable(obj) 
        and not isinstance(obj, (classmethod, staticmethod))
        and inspect.getmembers(cls, lambda m: m is obj)
    )

您应该从您认为最不可能的可能性中重新排序以上连接中的子句(以避免不必要的计算)。