[Python-ideas] The Descriptor Protocol...
Raymond Hettinger
raymond.hettinger at gmail.com
Wed Mar 2 17:10:15 CET 2011
On Mar 2, 2011, at 1:05 AM, Martin Chilvers wrote:
> G'day!
>
> 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.
>
> According to Raymond Hettinger's "How-To Guide for Descriptors" at:-
>
> http://users.rcn.com/python/download/Descriptor.htm#invoking-descriptors
>
> The *pseudo* implementation of __getattribute__ is as follows:-
>
> def __getattribute__(self, key):
> "Emulate type_getattro() in Objects/typeobject.c"
> v = object.__getattribute__(self, key)
> if hasattr(v, '__get__'):
> return v.__get__(None, self)
> return v
>
> 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?
I've gotten this question a couple times. There usual answers are:
* Why? Because Guido implemented it that way ;-)
* 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.
> 2) It makes the implementation of some descriptor based tools much uglier. Take for example a type specification tool, we might have something like:-
>
> class Person(object):
> name = Str()
> address = Str()
>
> 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:-
>
> a) using a metaclass to harvest the descriptors and set the attribute name. This is fine, but:-
> - it forces me to use a metaclass ;^)
> - it means that I can't share descriptors because they are bound to
> a particular attribute name which has obvious scaleability
> implications.
>
> b) make the developer duplicate the attribute name when constructing the descriptor:-
>
> class Person(object):
> name = Str('name')
> address = Str('address')
>
> which, well, just smells, and conflicts with step 3 of TDD ;^)
Yes, option b is the usual way to do it (there are a number of recipes that use this approach).
For the most part, that shouldn't be an unfamiliar pattern to Python developers. For example, named tuples repeat the name:
Point = namedtuple('Point', ('x', 'y')).
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.
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.
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.
Raymond
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20110302/51071e38/attachment.html>
More information about the Python-ideas
mailing list