<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><br><div><div>On Mar 2, 2011, at 1:05 AM, Martin Chilvers wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div>G'day!<br><br>Please excuse me if I have missed something obvious, but I have a question about the implementation of the descriptor protocol, and more specifically about the arguments passed to the '__get__' and '__set__' methods.<br><br>According to Raymond Hettinger's "How-To Guide for Descriptors" at:-<br><br><a href="http://users.rcn.com/python/download/Descriptor.htm#invoking-descriptors">http://users.rcn.com/python/download/Descriptor.htm#invoking-descriptors</a><br><br>The *pseudo* implementation of __getattribute__ is as follows:-<br><br>def __getattribute__(self, key):<br>    "Emulate type_getattro() in Objects/typeobject.c"<br>    v = object.__getattribute__(self, key)<br>    if hasattr(v, '__get__'):<br>       return v.__get__(None, self)<br>    return v<br><br>As mentioned above, this is obviously only pseudo-Python, but it serves to illustrate my question which is, why isn't the 'key' argument passed through to the '__get__' (and similarly, '__set__') methods?<br></div></blockquote><div><br></div><div>I've gotten this question a couple times.   There usual answers are:</div><div><br></div><div>* Why? Because Guido implemented it that way ;-)</div><div><br></div><div>* Why did he pick a signature that dropped the "key"?  Mostly likely, it is because none of the use-cases he had in mind required it.  The keyless API suffices to implement property(), super(), classmethod(), staticmethod(), bound method, __slots__, various features of new-style classes, and a reimplementation old-style classes.</div><div><br></div><div><br></div><br><blockquote type="cite"><div>2) It makes the implementation of some descriptor based tools much uglier. Take for example a type specification tool, we might have something like:-<br><br>class Person(object):<br>    name    = Str()<br>    address = Str()<br><br>where 'Str' is a descriptor. It would be nice to know in the '__get__' and '__set__' methods of 'Str' which attribute is being accessed. Of course, I can get around this by either:-<br><br>a) using a metaclass to harvest the descriptors and set the attribute name. This is fine, but:-<br>  - it forces me to use a metaclass ;^)<br>  - it means that I can't share descriptors because they are bound to<br>    a particular attribute name which has obvious scaleability<br>    implications.<br><br>b) make the developer duplicate the attribute name when constructing the descriptor:-<br><br>class Person(object):<br>    name    = Str('name')<br>    address = Str('address')<br><br>which, well, just smells, and conflicts with step 3 of TDD ;^)<font class="Apple-style-span" color="#000000"><font class="Apple-style-span" color="#144FAE"><br></font></font></div></blockquote><div><br></div><div>Yes, option b is the usual way to do it (there are a number of recipes that use this approach).</div><div><br></div><div>For the most part, that shouldn't be an unfamiliar pattern to Python developers.  For example, named tuples repeat the name:</div><div>   Point = namedtuple('Point', ('x', 'y')).   </div><div><br></div><div>Sometimes the language provides syntax to do the work for us, like "class A: ..." instead of "A = type('A', (), {})", but for other situations, it isn't unusual to pass in a name as a string literal so that an object will know its own name.</div><div><br></div><div>For Python 4, perhaps you can convince Guido to add a key argument to the signature for __get__ and __set__.  It would make a handful of recipes a bit prettier at the expense of being a total waste for all the other use cases that don't need it.</div><div><br></div><div>I think everyone who writes a descriptor that needs the "key" will chafe at the current design.  It bugged me at first, but the workaround is easy and after a while it doesn't seem as bothersome.</div><div><br></div><div><br></div><div>Raymond</div><div><br></div><div><br></div><div><br></div></div></body></html>