什么是“可调用”?

368 投票
13 回答
348832 浏览
提问于 2025-04-11 09:18

现在我们已经搞清楚了元类是什么,但还有一个相关的概念,我一直在用,却不知道它到底是什么意思。

我想大家都曾经因为括号用错而犯过错误,导致出现“对象不可调用”的异常。而且,使用__init____new__的时候,常常会让人想知道这个让人头疼的__call__到底是用来干什么的。

你能给我一些解释吗,最好能举些例子来说明这个魔法方法的用法?

13 个回答

46

可调用对象是指那些可以用圆括号 ( ) 来调用的对象,并且可以传递一些参数,就像函数一样。

每次你定义一个函数时,Python 就会创建一个可调用对象。比如,你可以用以下几种方式定义函数 func(其实是一样的):

class a(object):
    def __call__(self, *args):
        print 'Hello'

func = a()

# or ... 
def func(*args):
    print 'Hello'

你可以用这种方式来代替像 doitrun 这样的调用方法,我觉得直接用 obj() 看起来更清晰,而不是 obj.doit()。

92

来自Python的源代码 object.c:

/* Test whether an object can be called */

int
PyCallable_Check(PyObject *x)
{
    if (x == NULL)
        return 0;
    if (PyInstance_Check(x)) {
        PyObject *call = PyObject_GetAttrString(x, "__call__");
        if (call == NULL) {
            PyErr_Clear();
            return 0;
        }
        /* Could test recursively but don't, for fear of endless
           recursion if some joker sets self.__call__ = self */
        Py_DECREF(call);
        return 1;
    }
    else {
        return x->ob_type->tp_call != NULL;
    }
}

内容说明:

  1. 如果一个对象是某个类的实例,那么只有当它有一个叫做 __call__ 的属性时,它才是可调用的。
  2. 否则,对象 x 是可调用的,只有当 x->ob_type->tp_call != NULL

关于 tp_call 字段的描述:

ternaryfunc tp_call 是一个可选的指针,指向一个实现对象调用的函数。如果对象不可调用,这个指针应该是 NULL。它的签名和 PyObject_Call() 一样。这个字段会被子类继承。

你可以随时使用内置的 callable 函数来判断一个对象是否可调用;或者更简单地,直接调用它,如果出错再捕捉 TypeError。在Python 3.0和3.1中,callable 被移除了,可以用 callable = lambda o: hasattr(o, '__call__')isinstance(o, collections.Callable) 来替代。

举个例子,下面是一个简单的缓存实现:

class Cached:
    def __init__(self, function):
        self.function = function
        self.cache = {}

    def __call__(self, *args):
        try: return self.cache[args]
        except KeyError:
            ret = self.cache[args] = self.function(*args)
            return ret    

使用方法:

@Cached
def ack(x, y):
    return ack(x-1, ack(x, y-1)) if x*y else (x + y + 1) 

来自标准库的例子,文件 site.py,内置的 exit()quit() 函数的定义:

class Quitter(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'Use %s() or %s to exit' % (self.name, eof)
    def __call__(self, code=None):
        # Shells like IDLE catch the SystemExit, but listen when their
        # stdin wrapper is closed.
        try:
            sys.stdin.close()
        except:
            pass
        raise SystemExit(code)
__builtin__.quit = Quitter('quit')
__builtin__.exit = Quitter('exit')
360

可调用的东西就是指那些可以被“调用”的东西。

内置的 可调用 检查器(在 objects.c 文件中的 PyCallable_Check)会判断传入的参数是否:

  • 是一个有 __call__ 方法的类的实例,或者
  • 是某种类型,它有一个非空的 tp_call(C 结构体)成员,这个成员表示它是可以被调用的(比如函数、方法等)。

名为 __call__ 的方法是(根据文档

当这个实例被“调用”像一个函数一样时,会执行这个方法。

示例

class Foo:
  def __call__(self):
    print 'called'

foo_instance = Foo()
foo_instance() #this is calling the __call__ method

撰写回答