[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