什么是“可调用”?

新手上路,请多包涵

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

我想每个人都犯过一次括号错误,导致“对象不可调用”异常。更重要的是,使用 __init____new__ 让人想知道这个该死的 __call__ 能用来干什么。

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

原文由 e-satis 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 290
2 个回答

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

内置 可调用 对象(objects.c 中的 PyCallable_Check) 检查参数是否为:

  • 具有 __call__ 方法的类的实例或
  • 是一种具有非空 _tpcall (c struct) 成员的类型,该成员指示可调用性(例如在函数、方法等中)

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

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

例子

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

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

原文由 Florian Bösch 发布,翻译遵循 CC BY-SA 4.0 许可协议

来自 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 是可调用的 iff x->ob_type->tp_call != NULL

tp_call 字段 的描述:

ternaryfunc tp_call 一个可选的指针,指向实现调用对象的函数。如果对象不可调用,则这应该为 NULL。签名与 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')

原文由 jfs 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题