[Python-ideas] Adding __getter__ to compliment __iter__.

Nick Coghlan ncoghlan at gmail.com
Thu Jul 18 11:08:18 CEST 2013


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" :)

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

    def finish(self):
        "Converts the contents of the builder to the final desired type"

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()

Cheers,
Nick.

--
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list