【问题标题】:What is a "callable"?什么是“可调用”?
【发布时间】:2010-09-11 19:01:41
【问题描述】:

现在很清楚what a metaclass is,有一个相关的概念,我一直在使用,但不知道它的真正含义。

我想每个人都犯了一次括号错误,导致“对象不可调用”异常。更何况,使用__init____new__ 会让人想知道这个该死的__call__ 可以用来做什么。

你能给我一些解释,包括魔术方法的例子吗?

【问题讨论】:

标签: python callable


【解决方案1】:

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

built-in callable (PyCallable_Check in objects.c) 检查参数是否为:

  • 具有__call__ 方法的类的实例或
  • 属于具有非空 tp_call (c struct) 成员的类型,该成员表示可调用性(例如在函数、方法等中)

名为__call__的方法是(according to the documentation)

当实例作为函数被“调用”时调用

示例

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

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

【讨论】:

  • 请注意,内置可调用对象在 Python 3.0 中被删除,以支持检查 call
  • @Eli:嗯,这听起来像一个非常糟糕的举动。 callable 实际上会告诉您某些内容是否可调用,而检查 __call__ 不会告诉您任何内容;如果对象o 提供__getattribute____getattr__hasattr(o, '__call__') 可能会返回True,但o 仍然无法调用,因为Python 跳过__getattribute____getattr__ 进行调用。因此,检查某些东西是否可调用的唯一真正方法是 EAFP。
  • @Longpoke:仅作记录,请参阅the documentation for callable() in Python 3.x:“此函数首先在 Python 3.0 中被删除,然后在 Python 3.2 中被带回。”。跨度>
  • 在 python 3.8 中似乎只检查了 tp_call 的存在。请参阅PyCallable_Check 的实现,它是 3 行。
  • @MichelePiccolini 实际上已经有十多年的历史了,但它仍然可以执行它记录的操作,即检查某些东西是否可调用。当 Python 3 还很年轻时,他们改变了实现,现在带有 __call__ 方法的对象也总是有 tp_call 设置。我不确定“所有可调用对象都具有tp_call”何时实施,但PyCallable_Check 更改发生在 2006 年 8 月github.com/python/cpython/commit/…
【解决方案2】:

来自 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. 如果一个对象是某个类的实例,那么它是可调用的iff它具有__call__ 属性。
  2. 否则对象 x 是可调用的 iff x->ob_type->tp_call != NULL

tp_call field的描述:

ternaryfunc tp_call 可选 指向实现的函数的指针 调用对象。这应该是 如果对象不可调用,则为 NULL。 签名与 for 相同 PyObject_Call()。这个字段是 由子类型继承。

您总是可以使用内置的callable 函数来确定给定对象是否可调用;或者更好的是,只需调用它并稍后捕获TypeErrorcallable 在 Python 3.0 和 3.1 中被删除,使用 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')

【讨论】:

  • 我发现 call 方法的示例具有很大的误导性,因为它将它与缓存和装饰器的配方混合在一起,这对 call 的理解没有任何帮助b>
  • J.F.塞巴斯蒂安(Sebastian),还堆积了更多您从其他地方复制和粘贴的示例,这些示例并没有帮助。
  • @J.F.塞巴斯蒂安: 更逼真的例子更好,这是BS。我可以向你展示让你哭泣的栩栩如生的代码作为例子。简单的例子也很有效,它们更能说明一些事情,因为它们不会分散注意力。
  • 您正在解释什么是可调用对象,但您提供了一个示例,如何使用可调用对象来定义装饰器。我知道这是 callable 的典型用法,但这会让只想知道什么是可调用的以及如何使用 callable 的读者感到困惑。我更喜欢@Florian Bösch 的回答。
  • @Kay:我也喜欢@Florian Bösch 的回答(以目前的形式)。顺便说一句,装饰器不是“可调用”的典型用法。最典型的“可调用对象”是诸如def f(): ... 之类的函数/方法,以及诸如class C: ...f''.striplenC 之类的类对象都是可调用的。在其类中具有__call__() 方法的实例相对较少。
【解决方案3】:

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

每次定义函数时,python 都会创建一个可调用对象。 例如,您可以通过以下方式定义函数 func(相同):

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

func = a()

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

你可以用这个方法代替doitrun之类的方法,我认为obj()比obj.doit()更清楚

【讨论】:

    【解决方案4】:

    让我倒过来解释一下:

    考虑一下...

    foo()
    

    ...作为语法糖:

    foo.__call__()
    

    其中foo 可以是响应__call__ 的任何对象。当我说任何对象时,我的意思是:内置类型、您自己的类及其实例。

    在内置类型的情况下,当你写:

    int('10')
    unicode(10)
    

    你实际上是在做:

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

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

    【讨论】:

    • 你实际上是在做type(int).__call__(int, '10')type(unicode).__call__(unicode, '10')。 Dunders 总是在他们的类上被调用,而不是通过实例。他们也从不通过元类。在大多数情况下,这只是一个挑剔,但有时它很重要。
    【解决方案5】:

    Callable 是具有__call__ 方法的对象。这意味着您可以伪造可调用函数或做类似Partial Function Application 之类的简洁操作,您可以在其中获取一个函数并添加一些增强它的东西或填充一些参数,返回一些可以依次调用的东西(在功能中称为Currying编程圈)。

    某些印刷错误会使解释器尝试调用您不打算调用的内容,例如(例如)字符串。这可能会在解释器尝试执行不可调用的应用程序时产生错误。你可以在 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
    >>> 
    

    【讨论】:

      【解决方案6】:

      __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()”会告诉你某些东西是否可以调用,就像检查 call 属性一样。函数是可调用的,类也是可调用的,类实例也是可调用的。查看更多有关此herehere 的信息。

        【讨论】:

          【解决方案8】:

          在 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
          

          【讨论】:

            【解决方案9】:

            你可以在后面加上“(args)”并期望它起作用。可调用对象通常是方法或类。方法被调用,类被实例化。

            【讨论】:

              【解决方案10】:

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

              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
              

              【讨论】:

              • 你确定callable(obj.__init___) 没有额外的下划线(如在 AttributeError 中)?如果不是,你确定那个答案不是True 吗?
              【解决方案11】:

              callables 实现了__call__ 特殊方法,因此任何具有这种方法的对象都是可调用的。

              【讨论】:

              • 如果类没有定义这样的方法,您定义 __call__ 的实例将无法调用。
              【解决方案12】:

              Callable 是带有方法的“内置函数或方法”的类型或类 打电话

              >>> type(callable)
              <class 'builtin_function_or_method'>
              >>>
              

              示例: print 是一个可调用对象。使用内置函数 call 当您调用 print 函数时,Python 会创建一个 print 类型的对象 并调用其方法 call 传递参数如果有的话。

              >>> type(print)
              <class 'builtin_function_or_method'>
              >>> print.__call__(10)
              10
              >>> print(10)
              10
              >>>
              

              【讨论】:

              • 这里的一些信息是错误的。例如。 “当你调用 print 函数时,Python 会创建一个 print 类型的对象并调用它的方法 __call__”。 Python 不会创建打印对象。它只是调用相当于type(print).__call__(print, *args, **kwargs) 的东西。而且第一句话没有多大意义。您似乎混淆了可调用对象和“可调用”函数。
              猜你喜欢
              • 2014-09-16
              • 2013-10-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-02-11
              • 2015-11-24
              相关资源
              最近更新 更多