[Python-ideas] Fix that broken callable builtin

Ionel Cristian Mărieș contact at ionelmc.ro
Fri Apr 17 22:45:54 CEST 2015


Hello,

I had an issue today with the `callable` builtin because it doesn't
correctly check that the object has the __call__ attribute.

Effectively what `callable(a)` does is `hasattr(type(a), '__call__')` but
that's not very straightforward. A more straightforward implementation
would do something like `hasattr(a, '__call__')`.

For example:

Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 64
> bit (AMD64)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
> >>> callable
> <built-in function callable>
> >>> class A:
> ...  @property
> ...  def __call__(self):
> ...   raise AttributeError('go away')
> ...
> >>> a = A()
> >>> a
> <__main__.A object at 0x000000000365B5C0>
> >>> a.__call__
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "<stdin>", line 4, in __call__
> AttributeError: go away
> >>> callable(a)
> True
> >>> # it should be False :(
>

​So it boils down to this:

> >>> hasattr(a, "__call__")
> False
> >>> hasattr(type(a), "__call__")
> True


My issue is that I didn't call `callable(type(a))` but just `callable(a)`.
Clearly mismatching what happens when you do hasattr(a, "__call__").

To put in contrast, this is legal and clearly indicates the descriptors are
being used as expected:

>>> class B:
> ...  @property
> ...  def __call__(self):
> ...   return lambda: 1
> ...
> >>> b = B()
> >>> b()
> 1
>

​There​
​'s some more discussing in issue 23990 <http://bugs.python.org/issue23990>​
​ where I get slightly angry, sorry.​


​So were is this change actually useful? Proxies! Since new-style objects
in Python you cannot really proxy the callable aspect of objects, because
`callable` just checks that a field is set in a C struct.​
​ This is fairly inconvenient because you have to know upfront if your
target is going to be callable or not.​



Thanks,
-- Ionel Cristian Mărieș, http://blog.ionelmc.ro
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20150417/3298cce6/attachment.html>


More information about the Python-ideas mailing list