4

背景:我试图理解为什么静态和类方法在作为描述符时不可调用,而类的普通方法(即既不是静态方法也不是类方法的类的方法)和不是类属性的函数都是描述符并且可以调用。

在 Python 中,可调用类型的定义是什么?

  1. 来自https://docs.python.org/3/reference/datamodel.html

    可调用类型这些是可以应用函数调用操作(参见调用部分)的类型:

    运算符是“函数调用操作”()吗?那么可调用类型是否定义为()可以应用函数调用运算符的实例的类型?

  2. 来自https://docs.python.org/3/reference/expressions.html#calls

    主对象必须评估为可调用对象(用户定义的函数、内置函数、内置对象的方法、类对象、类实例的方法以及所有具有 __call__()方法的对象都是可调用的)。

    这是否意味着可调用类型可能有也可能没有 __call__()方法?如果一个类有一个__call__()方法,那么它一定是一个可调用的类型吗?如果一个类没有__call__() 方法,那么它可能是也可能不是可调用类型?

    “自定义函数、内置函数、内置对象的方法、类对象、类实例的方法”没有 __call__()方法吗?它们是可调用类型的实例吗?它们分别有哪些具体类型?

谢谢。

4

2 回答 2

4

运算符是“函数调用操作”()吗?那么可调用类型是否定义为()可以应用函数调用运算符的实例的类型?

对,就是这样。

这是否意味着可调用类型可能有也可能没有__call__()方法?如果一个类有一个__call__()方法,那么它一定是一个可调用的类型吗?如果一个类没有__call__()方法,那么它可能是也可能不是可调用类型?

要使给定对象成为可调用对象,它必须定义__call__函数,例如:

def foo():
    pass
callable(foo) # True

staticmethod's 或classmethods (从上一个问题继续),不要定义__call__

s = staticmethod(foo)
callable(s)  # False

callable基本上做类似的事情getattr(foo, '__call__', False)

“自定义函数、内置函数、内置对象的方法、类对象、类实例的方法”难道没有call ()方法吗?它们是可调用类型的实例吗?它们分别有哪些具体类型?

  • 用户定义的函数(function类型,like foo)有__call__.

  • 内置函数(例如max)也有__call__,请参阅callable(max)

  • 内置对象的方法,是的:callable(str.isupper).

  • 类对象,是的(为它们type定义一个__call__):

    >>> class Spam: pass
    >>> callable(Spam) # True
    
  • 类实例的方法:

    >>> class Spam2: 
    ...     def do_spam(self):
    ...         return "spam"
    ...
    >>> callable(Spam2().do_spam)  # True
    

它们都是可调用的,因为它们定义了一个__call__特殊的方法。这是使对象可调用的唯一方法。

至于静态方法和类方法,虽然它们通常包装可调用对象(然后通过描述符协议公开),但它们本身是不可调用的,因为它们没有定义__call__特殊方法。

于 2017-09-17T12:32:44.023 回答
1

检查 Callable 的定义

from collections import Callable

源代码如下:

class Callable(metaclass=ABCMeta):

    __slots__ = ()

    @abstractmethod
    def __call__(self, *args, **kwds):
        return False

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Callable:
            if any("__call__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented

棘手的部分是__subclasshook__的方法,因此任何可以找到 __call__ 方法的类都可以被视为 Callable 的子类,而不是直接从它继承。

PS:不仅__subclasshook__可以做到这一点,register()方法还可以将另一个类注册为基类的子类。

于 2017-09-17T11:36:19.800 回答