[Python-ideas] Adding __getter__ to compliment __iter__.
Ron Adam
ron3200 at gmail.com
Thu Jul 18 16:29:37 CEST 2013
On 07/18/2013 04:08 AM, Nick Coghlan wrote:
> On 18 July 2013 16:46, Ron Adam <ron3200 at gmail.com> wrote:
>>
>>
>> These methods would be called by a getter function which starts it by
>> calling next on it before returning it.
>>
>>
>> def getter(container):
>> """ Get a getter from a container object. """
>> g = container.__getter__()
>> next(g)
>> return g
>
> Let's call it the "builder" protocol instead, since "getter" makes me
> think of "itemgetter" and "attrgetter", and this is well worn
> territory in Java with "StringBuilder" :)
Is fine with me. The name "getter" was the first thing I thought of.
> Let's say we defined the builder protocol this way:
>
> 1. Containers may define a "__builder__" method:
>
> def __builder__(self):
> "Returns a builder for a *new* instance of this type,
> pre-initialised with the contents of self"
>
> 2. Builders must define the following methods:
>
> def append(self, item):
> "Appends a single item to the builder"
>
> def extend(self, iterable):
> "Extends the builder with the contents of an iterable"
>
> __iadd__ = extend
This is interesting.
> def finish(self):
> "Converts the contents of the builder to the final desired type"
I was thinking a generator would be more efficient if it's called many
times. But I think this is easier to understand. If there is more
interest we can test both to see how much of a difference it makes.
> And added a new "builder" builtin with the following behaviour:
>
> def builder(obj):
> try:
> meth = obj.__builder__
> except AttributeError:
> pass
> else:
> return meth
> return DefaultBuilder(obj)
>
> class DefaultBuilder:
> def __init__(self, obj):
> if not (hasattr(obj, "copy") and hasattr(obj, "append")
> and hasattr(obj, "extend")):
> raise TypeError("%r instance cannot be converted to a
> builder" % type(r))
> self._obj = obj.copy()
>
> def append(self, item):
> if self._obj is None: raise RuntimeError("Cannot append to
> finished builder")
> self._obj.append(item)
>
> def extend(self, iterable):
> if self._obj is None: raise RuntimeError("Cannot extend
> finished builder")
> self._obj.extend(iterable)
>
> __iadd__ = extend
>
> def finish(self):
> if self._obj is None: raise RuntimeError("Builder already finished")
> result = self._obj
> self._obj = None
> return result
>
> Then builtin sum() would have the following case added to handle the
> builder protocol:
>
> try:
> bldr = builder(start)
> except TypeError:
> pass
> else:
> for item in iterable:
> bldr += item
> return bldr.finish()
Yes, that would do it... and is a good example.
Cheers,
Ron
More information about the Python-ideas
mailing list