[Python-ideas] Fix that broken callable builtin

Steven D'Aprano steve at pearwood.info
Sat Apr 18 12:26:34 CEST 2015


On Fri, Apr 17, 2015 at 02:10:30PM -0700, Ethan Furman wrote:
> On 04/18, Ionel Cristian Mărieș wrote:
> 
> > Also there's the issue about not being able to implement a true proxy (as
> > outlined before).
> 
> Proxies are a bit of a pain.  But you can create your own callable function.
> 
> Something like (untested):
> 
> def callable(obj):
>     try:
>         func = obj.__call__
>         return True
>     except AttributeError:
>         return False

You can define it like that, but it doesn't work.

Using the above definition of callable:

py> class Spam(object):
...     pass
...
py> x = Spam()
py> x.__call__ = lambda self: 23
py> callable(x)
True
py> x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'Spam' object is not callable


"foo()" syntax does not look for a __call__ method on the instance, only 
on the type. The current behaviour of callable is correct:

py> builtins.callable(x)
False

With new-style classes (but not classic classes), all dunder methods are 
only accessed through the class, not the instance. Hence 
type(obj).__call__ is correct and obj.__call__ is incorrect.

Could this be changed? That deserves a new thread, at least, and 
possibly a PEP, but briefly:

(1) The current behaviour is documented, so it would require some form 
of transition;

(2) The current behaviour is intended as an optimization. Using Python 
2.7 on my system, I find that a minimal __add__ method is more than 
three times faster using a new-style class compared to a classic class.


-- 
Steve


More information about the Python-ideas mailing list