[Cython] callable() optimization

Stefan Behnel stefan_ml at behnel.de
Wed May 9 10:47:07 CEST 2012


mark florisson, 09.05.2012 10:37:
> On 9 May 2012 09:02, Stefan Behnel <stefan_ml at behnel.de> wrote:
>> Vitja Makarov, 09.05.2012 09:43:
>>> 2012/5/9 Stefan Behnel <stefan_ml at behnel.de>:
>>>> Vitja Makarov, 08.05.2012 13:27:
>>>>> I've noticed regression related to callable() optimization.
>>>>>
>>>>> https://github.com/cython/cython/commit/a40112b0461eae5ab22fbdd07ae798d4a72ff523
>>>>>
>>>>> class C:
>>>>>     pass
>>>>> print callable(C())
>>>>>
>>>>> It prints True optimized version checks ((obj)->ob_type->tp_call !=
>>>>> NULL) condition that is True for both class and instance.
>>>>>
>>>>>>>> help(callable)
>>>>> callable(...)
>>>>>     callable(object) -> bool
>>>>>
>>>>>     Return whether the object is callable (i.e., some kind of function).
>>>>>     Note that classes are callable, as are instances with a __call__() method.
>>>>
>>>> Ah, right - old style classes are special cased in Py2.
>>>>
>>>> I'll make this a Py3-only optimisation then.
>>>>
>>>
>>> I don't see difference between py2 and py3 here:
>>>
>>> Python 3.2.3 (default, May  3 2012, 15:51:42)
>>> [GCC 4.6.3] on linux2
>>> Type "help", "copyright", "credits" or "license" for more information.
>>>>>> class Foo: pass
>>> ...
>>>>>> callable(Foo())
>>> False
>>>>>>
>>>
>>> There is PyCallable_Check() CPython function:
>>>
>>> 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;
>>>     }
>>> }
>>
>> That's the Py2 version. In Py3, it looks as follows, because old-style
>> "instances" no longer exist:
>>
>> """
>> int
>> PyCallable_Check(PyObject *x)
>> {
>>        if (x == NULL)
>>                return 0;
>>        return x->ob_type->tp_call != NULL;
>> }
>> """
>>
>> That's what I had initially based my optimisation on.
> 
> Huh, so __call__ in a user defined new style class could never end up
> in ob_type.tp_call right?

Yes it does. CPython special cases these method names.

Stefan


More information about the cython-devel mailing list