“callable”是什么?

364

既然现在清楚了元类是什么,那么有一个相关的概念我经常使用,但不知道它真正的含义。

我想每个人都曾经因为括号的错误而导致"对象不可调用"的异常。更重要的是,使用__init____new__会让人想知道这该死的__call__可以用来做什么。

您能给我一些解释吗?包括使用魔术方法的示例。


13个回答

357

可调用对象是任何可以被调用的东西。

内置的callable(对象中的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

7
请注意,Python 3.0 中将删除内置的 callable,改为检查 call 方法。 - Eli Courtwright
18
@Eli:嗯,那听起来像是一个非常糟糕的举动。callable实际上告诉你某个东西是否可调用,而检查__call__并没有什么作用;如果一个对象o提供了__getattribute____getattr__hasattr(o, '__call__')可能会返回True,但是因为Python在调用时跳过__getattribute____getattr__,所以o仍然无法被调用。因此,检查某个东西是否可调用的唯一真正方法是EAFP。 - L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
65
仅供参考,Python 3.x中callable()函数的文档请见官方文档:"在Python 3.0中该函数被首次移除,然后在Python 3.2中重新引入。" - Tadeck
1
@MichelePiccolini 实际上,这种情况已经持续了十多年,但它仍然可以按照文档所述的方式进行检查是否可调用。当 Python 3 还很年轻时,他们改变了实现方式,现在具有 __call__ 方法的对象总是也设置了 tp_call。我不确定“所有可调用项都有 tp_call”是何时实现的,但 PyCallable_Check 的更改发生在 2006 年 8 月:https://github.com/python/cpython/commit/50e9fb9e2d6b4b12524116ab775ac6543e4a5332#diff-ba56d44ce0dd731d979970b966fde9d8dd15d12a82f727a052a8ad48d4a49363 - mtraceur
不论C实现检查了什么,值得注意的是在现代Python中,函数确实具有__call__属性,它被定义为表示该函数的method-wrapper实例。对于def x(): pass,我们有一个不变式,即x.__call__.__self__ is x - undefined
显示剩余3条评论

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->ob_type->tp_call != NULL时,对象x是可调用的。
对于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')

10
我发现__call__方法的例子非常误导,因为它将其与缓存和装饰器的配方混合在一起,这对于理解__call__没有任何帮助。 - Florian Bösch
3
J.F.塞巴斯蒂安,你把从别处复制粘贴的更多例子也堆积起来并不能有所帮助,因为它们不是最简单的。 - Florian Bösch
20
@J.F. Sebastian:更逼真的例子不一定更好。我可以给你展示一些逼真的代码,但这可能会让你哭泣。简单的例子同样有效,因为它们不会分散注意力,更容易说明问题。 - Florian Bösch
5
您正在解释什么是可调用对象,但您提供了一个使用可调用对象定义装饰器的示例。我知道这是__callable__的典型用法,但这可能会让只想知道什么是可调用对象以及如何使用__callable__的读者感到困惑。我更喜欢@Florian Bösch的答案。 - KFL
2
@Kay:我也喜欢@Florian Bösch的回答(目前的形式)。顺便说一下,装饰器并不是“可调用对象”的典型用法。最典型的“可调用对象”是函数/方法,例如def f(): ...和类对象,例如class C: ...f''.striplenC都是可调用的。在其类中具有__call __()方法的实例相对较少。 - jfs
显示剩余8条评论

46

可调用对象是一个允许您使用圆括号()并最终传递一些参数的对象,就像函数一样。

每当您定义一个函数时,Python都会创建一个可调用对象。例如,您可以以以下方式定义函数 func (它们是相同的):

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

func = a()

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

我认为使用obj()比使用doit()或run()等方法更加清晰易懂。


41

让我倒过来解释:

考虑这个...

foo()

...作为语法糖表示:

foo.__call__()

foo可以是任何响应__call__方法的对象。我所说的任何对象都是指:内置类型、您自己的类以及它们的实例。

就内置类型而言,当您编写:

int('10')
unicode(10)

你基本上正在做的是:

int.__call__('10')
unicode.__call__(10)

这也是为什么在Python中你没有foo = new int:你只需要让类对象在__call__上返回一个实例。我认为Python解决这个问题的方式非常优雅。


1
你实际上是在执行 type(int).__call__(int, '10')type(unicode).__call__(unicode, '10')。Dunder方法总是在它们的类上调用,而不是通过实例调用。它们也从不经过元类。对于大多数情况来说这只是一个小问题,但有时候确实很重要。 - Mad Physicist
1
内置类型在参考C实现中以特殊方式工作,尽管发生的事情本质上等价于此。对于用户定义的类型,编写MyClass()试图调用该类,通过查找MyClass 's class上的__call__方法来完成,即它跳过在MyClass内进行属性查找(否则它可能会找到一个为实例设计的用户定义的__call__!)并找到type.__call__-然后通过通常的机制评估为MyClass上的绑定方法,然后进行调用。 - Karl Knechtel

11

可调用对象是拥有__call__方法的对象。这意味着您可以模拟可调用函数,或者执行一些聪明的事情,例如偏函数应用,其中您获取一个函数并添加增强它或填充某些参数的东西,返回可以在其上调用的某些内容(在函数式编程圈子中称为柯里化)。

某些排版错误会导致解释器试图调用您不打算调用的内容,例如字符串。这可能会导致解释器尝试执行非可调用应用程序而出现错误。您可以通过以下交互式 Python 解释器操作查看此情况。

[nigel@k9 ~]$ python
Python 2.5 (r25:51908, Nov  6 2007, 15:55:44) 
[GCC 4.1.2 20070925 (Red Hat 4.1.2-27)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'aaa'()    # <== Here we attempt to call a string.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
>>> 

11

__call__ 使任何对象都可以作为函数进行调用。

以下示例将输出 8:

class Adder(object):
  def __init__(self, val):
    self.val = val

  def __call__(self, val):
    return self.val + val

func = Adder(5)
print func(3)

7
简单来说,“callable”是可以像方法一样调用的东西。内置函数“callable()”将告诉您是否可调用某个对象,检查“call”属性也可以。函数和类都是可调用的,类实例也可以被调用。关于此,请参见这里这里

1
稍微让读者有些困惑的是:类是可调用的,因为它们是一个具有可调用实例的类的实例。你可能听说过它:它被称为 type。这个对象是独一无二的,它是自己的类型,也是自己的实例。它定义了一个 __call__ 方法,以便类可以被调用;这就是在实际分配内存时调用实现特定魔法的地方,同时还可以使用类的 __new__ 钩子,然后在生成的对象上调用 __init__ - Karl Knechtel

6
在Python中,可调用对象是指具有__call__方法的对象:
>>> class Foo:
...  pass
... 
>>> class Bar(object):
...  pass
... 
>>> type(Foo).__call__(Foo)
<__main__.Foo instance at 0x711440>
>>> type(Bar).__call__(Bar)
<__main__.Bar object at 0x712110>
>>> def foo(bar):
...  return bar
... 
>>> type(foo).__call__(foo, 42)
42

就是这么简单 :)

当然,这也可以被重载:

>>> class Foo(object):
...  def __call__(self):
...   return 42
... 
>>> f = Foo()
>>> f()
42

4
这是一种可以在后面加上"(args)"并期望其正常工作的东西。可调用对象通常是方法或类。方法被调用,类被实例化。

3

检查类的函数或方法是否可调用,这意味着我们可以调用该函数。

Class A:
    def __init__(self,val):
        self.val = val
    def bar(self):
        print "bar"

obj = A()      
callable(obj.bar)
True
callable(obj.__init___)
False
def foo(): return "s"
callable(foo)
True
callable(foo())
False

2
你确定 callable(obj.__init___) 没有多一个下划线(例如 AttributeError)吗?如果没有,你确定答案不是 True 吗? - Mad Physicist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接