Nick Coghlan wrote:
Steven Bethard wrote:

Yes -- help me rally behind my generic object PEP which proposes a Bunch type (probably to be renamed) for the Python standard lib. =)

Did you see the suggestion of 'namespace' as a name?

Yup, it's in the current PEP draft. See the "Open Issues" section:


PEP: XXX Title: Generic Object Data Type Version: $Revision: 1.0 $ Last-Modified: $Date: 2004/11/29 16:00:00 $ Author: Steven Bethard <[EMAIL PROTECTED]> Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 29-Nov-2004 Python-Version: 2.5 Post-History: 29-Nov-2004


Abstract ========

This PEP proposes a standard library addition to support the simple
creation of 'generic' objects which can be given named attributes
without the need to declare a class. Such attribute-value mappings are
intended to complement the name-value mappings provided by Python's
builtin dict objects.


Motivation ==========

Python's dict objects provide a simple way of creating anonymous
name-value mappings. These mappings use the __getitem__ protocol to
access the value associated with a name, so that code generally appears
like::

    mapping['name']

Occasionally, a programmer may decide that dotted-attribute style access
is more appropriate to the domain than __getitem__ style access, and
that their mapping should be accessed like::

    mapping.name

Currently, if a Python programmer makes this design decision, they are
forced to declare a new class, and then build instances of this class.
When no methods are to be associated with the attribute-value mappings,
declaring a new class can be overkill.  This PEP proposes adding a
simple type to the collections module of the standard library that can
be used to build such attribute-value mappings.

Providing such a type allows the Python programmer to determine which
type of mapping is most appropriate to their domain and apply this
choice with minimal effort.  Some of the suggested uses include:


Returning Named Results -----------------------

It is often appropriate for a function that returns multiple items to
give names to the different items returned.  The type suggested in this
PEP provides a simple means of doing this that allows the returned
values to be accessed in the usual attribute-style access::

    >>> def f(x):
    ...     return Bunch(double=2*x, squared=x**2)
    ...
    >>> y = f(10)
    >>> y.double
    20
    >>> y.squared
    100


Representing Hierarchical Data ------------------------------

The type suggested in this PEP also allows a simple means of
representing hierarchical data that allows attribute-style access::

    >>> x = Bunch(spam=Bunch(rabbit=1, badger=[2, 3, 4]), ham='neewom')
    >>> x.spam.badger
    [2, 3, 4]
    >>> x.ham
    'neewom'


Rationale =========

As Bunch objects are intended primarily to replace simple, data-only
classes, simple Bunch construction was a primary concern.  As such,
the Bunch constructor supports creation from keyword arguments, dicts,
and sequences of (attribute, value) pairs::

    >>> Bunch(eggs=1, spam=2, ham=3)
    Bunch(eggs=1, ham=3, spam=2)
    >>> Bunch({'eggs':1, 'spam':2, 'ham':3})
    Bunch(eggs=1, ham=3, spam=2)
    >>> Bunch([('eggs',1), ('spam',2), ('ham',3)])
    Bunch(eggs=1, ham=3, spam=2)

To allow attribute-value mappings to be easily combined, the Bunch type
provides a update staticmethod that supports similar arguments::

    >>> bunch = Bunch(eggs=1)
    >>> Bunch.update(bunch, [('spam', 2)], ham=3)
    >>> bunch
    Bunch(eggs=1, ham=3, spam=2)

Note that update is available through the class, not through the
instances, to avoid the confusion that might arise if an 'update'
attribute added to a Bunch instance hid the update method.


If Bunch objects are used to represent hierarchical data, comparison of such objects becomes a concern. For this reason, Bunch objects support object equality which compares Bunch objects by attributes recursively::

    >>> x = Bunch(parrot=Bunch(lumberjack=True, spam=42), peng='shrub')
    >>> y = Bunch(peng='shrub', parrot=Bunch(spam=42, lumberjack=True))
    >>> z = Bunch(parrot=Bunch(lumberjack=True), peng='shrub')
    >>> x == y
    True
    >>> x == z
    False


Note that support for the various mapping methods, e.g. __(get|set|del)item__, __len__, __iter__, __contains__, items, keys, values, etc. was intentionally omitted as these methods did not seem to be necessary for the core uses of an attribute-value mapping. If such methods are truly necessary for a given use case, this may suggest that a dict object is a more appropriate type for that use.


Examples =========

Converting an XML DOM tree into a tree of nested Bunch objects::

    >>> import xml.dom.minidom
    >>> def getbunch(element):
    ...     result = Bunch()
    ...     if element.attributes:
    ...         Bunch.update(result, element.attributes.items())
    ...     children = {}
    ...     for child in element.childNodes:
    ...         if child.nodeType == xml.dom.minidom.Node.TEXT_NODE:
    ...             children.setdefault('text', []).append(
    ...                 child.nodeValue)
    ...         else:
    ...             children.setdefault(child.nodeName, []).append(
    ...                 getbunch(child))
    ...     Bunch.update(result, children)
    ...     return result
    ...
    >>> doc = xml.dom.minidom.parseString("""\
    ... <xml>
    ...   <a attr_a="1">
    ...     a text 1
    ...     <b attr_b="2" />
    ...     <b attr_b="3"> b text </b>
    ...     a text 2
    ...   </a>
    ...   <c attr_c="4"> c text </c>
    ... </xml>""")
    >>> b = getbunch(doc.documentElement)
    >>> b.a[0].b[1]
    Bunch(attr_b=u'3', text=[u' b text '])

Reference Implementation
========================

The code is available as SourceForge patch 1094542 [1]_.


Open Issues =========== What should the type be named? Some suggestions include 'Bunch', 'Record', 'Struct' and 'Namespace'.

Where should the type be placed?  The current suggestion is the
collections module.


References ==========

.. [1] http://sourceforge.net/tracker/index.php?func=detail&aid=1094542&group_id=5470&atid=305470


..
   Local Variables:
   mode: indented-text
   indent-tabs-mode: nil
   sentence-end-double-space: t
   fill-column: 70
   End:
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to