[Python-ideas] Fix that broken callable builtin

Guido van Rossum guido at python.org
Fri Apr 17 22:55:17 CEST 2015


I think you're fighting windmills. Like most special operations (e.g.
__add__), a __call__ attribute on the object does not work, i.e. it does
not make the object callable. E.g.

$ python3
Python 3.5.0a2 (v3.5.0a2:0337bd7ebcb6, Mar  8 2015, 01:12:06)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class C: pass
...
>>> c = C()
>>> c.__call__ = lambda *a: a
>>> c()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'C' object is not callable
>>> callable(c)
False
>>> hasattr(c, '__call__')
True
>>>

On Fri, Apr 17, 2015 at 1:45 PM, Ionel Cristian Mărieș <contact at ionelmc.ro>
wrote:

> 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
>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>



-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20150417/b52e1290/attachment-0001.html>


More information about the Python-ideas mailing list