[Cython] callable() optimization

Vitja Makarov vitja.makarov at gmail.com
Wed May 9 10:50:24 CEST 2012


2012/5/9 Stefan Behnel <stefan_ml at behnel.de>:
> Vitja Makarov, 09.05.2012 10:21:
>> 2012/5/9 Stefan Behnel <stefan_ml at behnel.de>:
>>> 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.
>>
>> Ok, so why don't you want to use PyCallable_Check() in all cases?
>
> Well, maybe this isn't performance critical enough to merit inlining. Do
> you think it matters?
>

Py3k case is quite simple expression so I think it may be inlined. On
the other hand it's not often used.

-- 
vitja.


More information about the cython-devel mailing list