Gregory Ewing wrote: > Steven D'Aprano wrote: >> Actually, if you look at my example, you will see that it is a method and >> it does get the self argument. Here is the critical code again: >> >> from types import MethodType >> polly.talk = MethodType( >> lambda self: print("Polly wants a spam sandwich!"), polly) > > Doing it by hand is cheating.
Smile when you say that, pardner :-) I don't see why you think I'm cheating. What rule do you think is being broken? I want to add a method to the instance itself, so I create a method object and put it on the instance. What should I have done? The default metaclass ("type") only applies the descriptor protocol to attributes retrieved from the class itself, not those retrieved from the instance. For instance, you can add a property object onto the instance, but it won't behave as a property: py> class K(object): ... pass ... py> x = K() py> x.spam = property(lambda self: 23) py> x.spam <property object at 0xb7bbcb44> But if I add it to the class, the descriptor magic happens: py> K.eggs = x.spam py> x.eggs 23 Functions are descriptors, just like property objects! So an alternative to manually making a method object would be to use a metaclass that extended the descriptor protocol to instance attributes. I suppose you would call that "cheating" too? But all of this is a side-show that distracts from my point, which is that the lookup rules for instances and classes are such that you can override behaviour defined in the class on a per-instance basis. The mechanics of such aren't really relevant. >> That's certainly not correct, because Python had classes and instances >> before it had descriptors! > > Before the descriptor protocol, a subset of its functionality > was hard-wired into the interpreter. There has always been > some magic going on across the instance-class boundary that > doesn't occur across the class-baseclass boundary. Yes, but that magic is effectively "implementation, not interface". I put that in scare quotes because in actual pedantic fact, the descriptor protocol is an interface: we can write our own custom descriptors. I don't dispute that's important. But from a birds eye view, and looking at just method and regular attribute access, the relationship between instance-class and class-baseclass is very similar, as is that between class-metaclass, and descriptor magic is merely part of the implementation to make things work. I daresay you are right that there are a few places where the interpreter treats classes as a distinct and different kind of thing than non-class instances. One obvious place is that dunder methods are not looked up on the instance, unlike pretty much everything else. But I did preface my comments about attribute lookup order as being simplified, so you can probably find a lot more to criticise if you wish :-) -- Steven -- https://mail.python.org/mailman/listinfo/python-list