[Python-ideas] Fix that broken callable builtin

Ionel Cristian Mărieș contact at ionelmc.ro
Sat Apr 18 12:41:04 CEST 2015


On Sat, Apr 18, 2015 at 1:26 PM, Steven D'Aprano <steve at pearwood.info>
wrote:

>
> 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.


​Yes, this is correct. But unfortunately is also very commonly
misunderstood, because even special methods will work through the
descriptor protocol. The __new__ method is the only special case here (the
infamous "special cased static method").

py> x.__call__ = lambda self: 23
>

The issue never was about patching __call__ on an instance, it's about
making  `callable` respect how the method is actually looked up fully
(lookup on type + descriptor protocol). What `callable` is missing now is
an additional check that will run the descriptor protocol.

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


​So what exactly are you proposing, making a PEP that documents the fact
that functions are descriptors and the descriptor protocol is used even for
special methods?

To give more context here, this is valid and it works right now:

​>>> class NonIter:
> ...     pass
> ...
> >>> iter(NonIter())
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> TypeError: 'NonIter' object is not iterable
> >>>
> >>> class DynamicNonIter:
> ...     has_iter = False
> ...
> ...     @property
> ...     def __iter__(self):
> ...         if self.has_iter:
> ...             from functools import partial
> ...             return partial(iter, [1, 2, 3])
> ...         else:
> ...             raise AttributeError("Not really ...")
> ...
> >>> dni = DynamicNonIter()
> >>> iter(dni)
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> TypeError: 'DynamicNonIter' object is not iterable
> >>> dni.has_iter = True
> >>> iter(dni)
> <list_iterator object at 0x000000000362FF60>


​I don't see why `callable` shouldn't work the same.​


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/20150418/3af8276b/attachment.html>


More information about the Python-ideas mailing list