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