[Cython] callable() optimization

mark florisson markflorisson88 at gmail.com
Wed May 9 10:37:58 CEST 2012


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.
>
> Stefan
> _______________________________________________
> cython-devel mailing list
> cython-devel at python.org
> http://mail.python.org/mailman/listinfo/cython-devel

Huh, so __call__ in a user defined new style class could never end up
in ob_type.tp_call right? So how can it avoid that dict lookup?


More information about the cython-devel mailing list