What is a “callable”?

前端 未结 12 2392
谎友^
谎友^ 2020-11-22 01:23

Now that it\'s clear what a metaclass is, there is an associated concept that I use all the time without knowing what it really means.

I suppose everybody made once

12条回答
  •  半阙折子戏
    2020-11-22 02:03

    From Python's sources 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;
        }
    }
    

    It says:

    1. If an object is an instance of some class then it is callable iff it has __call__ attribute.
    2. Else the object x is callable iff x->ob_type->tp_call != NULL

    Desciption of tp_call field:

    ternaryfunc tp_call An optional pointer to a function that implements calling the object. This should be NULL if the object is not callable. The signature is the same as for PyObject_Call(). This field is inherited by subtypes.

    You can always use built-in callable function to determine whether given object is callable or not; or better yet just call it and catch TypeError later. callable is removed in Python 3.0 and 3.1, use callable = lambda o: hasattr(o, '__call__') or isinstance(o, collections.Callable).

    Example, a simplistic cache implementation:

    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    
    

    Usage:

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

    Example from standard library, file site.py, definition of built-in exit() and quit() functions:

    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')
    

提交回复
热议问题