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