[Python-ideas] Fix that broken callable builtin

Steven D'Aprano steve at pearwood.info
Sat Apr 18 13:23:32 CEST 2015


On Sat, Apr 18, 2015 at 01:41:04PM +0300, Ionel Cristian Mărieș wrote:
> 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").

I must admit that until now I had never even thought about making a 
property with a dunder name. But now that I have considered it, why 
should it not work? The property (or other descriptor) is on the class, 
not the instance.

py> class Test(object):
...     @property
...     def __len__(self):
...             return lambda: 42
...
py> x = Test()
py> len(x)
42
py> type(x).__len__.__get__(x, type(x))()
42

But this won't work on the instance.


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

Okay, I misunderstood you, my apologies. I was mislead by your original 
suggestion to use hasattr(x, '__call__'), sorry about that.

Are you sure this doesn't already work? It works for me in Python 3.3:

py> class CallableTest(object):
...     @property
...     def __call__(self):
...             def inner(arg1, arg2):
...                     return [self, "called with", arg1, arg2]
...             return inner
...
py> x = CallableTest()
py> x(1, 2)
[<__main__.CallableTest object at 0xb7b9072c>, 'called with', 1, 2]
py> callable(x)
True

but perhaps I have missed something.


> > ​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?

No, I thought you wanted dunder methods to be used from the instance 
__dict__, like with classic classes. If that is not your intent, then my 
comments about a PEP are irrelevant.


-- 
Steve


More information about the Python-ideas mailing list