## With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

No credit card required

# Collecting a Bunch of Named Items

Credit: Alex Martelli

## Problem

You want to collect a bunch of items together, naming each item of the bunch, and you find dictionary syntax a bit heavyweight for the purpose.

## Solution

Any (classic) class inherently wraps a dictionary, and we take advantage of this:

```class Bunch:
def _ _init_ _(self, **kwds):
self._ _dict_ _.update(kwds)```

Now, to group a few variables, create a `Bunch` instance:

`point = Bunch(datum=y, squared=y*y, coord=x)`

You can access and rebind the named attributes just created, add others, remove some, and so on. For example:

```if point.squared > threshold:
point.isok = 1```

## Discussion

Often, we just want to collect a bunch of stuff together, naming each item of the bunch; a dictionary’s okay for that, but a small do-nothing class is even handier and is prettier to use.

A dictionary is fine for collecting a few items in which each item has a name (the item’s key in the dictionary can be thought of as the item’s name, in this context). However, when all names are identifiers, to be used just like variables, the dictionary-access syntax is not maximally clear:

`if point['squared'] > threshold`

It takes minimal effort to build a little class, as in this recipe, to ease the initialization task and provide elegant attribute-access syntax:

`if bunch.squared > threshold`

An equally attractive alternative implementation to the one used in the solution is:

```class EvenSimplerBunch:
def _ _init_ _(self, **kwds): self._ _dict_ _ = kwds```

The alternative presented in the `Bunch` class has the advantage of not rebinding `self._ _dict_ _` (it uses the dictionary’s `update` method to modify it instead), so it will keep working even if, in some hypothetical far-future dialect of Python, this specific dictionary became nonrebindable (as long, of course, as it remains mutable). But this `EvenSimplerBunch` is indeed even simpler, and marginally speedier, as it just rebinds the dictionary.

It is not difficult to add special methods to allow attributes to be accessed as `bunch['squared']` and so on. In Python 2.1 or earlier, for example, the simplest way is:

```import operator

class MurkierBunch:
def _ _init_ _(self, **kwds):
self._ _dict_ _ = kwds
def _ _getitem_ _(self, key):
return operator.getitem(self._ _dict_ _, key)
def _ _setitem_ _(self, key, value):
return operator.setitem(self._ _dict_ _, key, value)
def _ _delitem_ _(self, key):
return operator.delitem(self._ _dict_ _, key)```

In Python 2.2, we can get the same effect by inheriting from the `dict` built-in type and delegating the other way around:

```class MurkierBunch22(dict):
def _ _init_ _(self, **kwds): dict._ _init_ _(self, kwds)
_ _getattr_ _ = dict._ _getitem_ _
_ _setattr_ _ = dict._ _setitem_ _
_ _delattr_ _ = dict._ _delitem_ _```

Neither approach makes these `Bunch` variants into fully fledged dictionaries. There are problems with each—for example, what is `someBunch.keys` supposed to mean? Does it refer to the method returning the list of keys, or is it just the same thing as `someBunch['keys']`? It’s definitely better to avoid such confusion: Python distinguishes between attributes and items for clarity and simplicity. However, many newcomers to Python do believe they desire such confusion, generally because of previous experience with JavaScript, in which attributes and items are regularly confused. Such idioms, however, seem to have little usefulness in Python. For occasional access to an attribute whose name is held in a variable (or otherwise runtime-computed), the built-in functions `getattr`, `setattr`, and `delattr` are quite adequate, and they are definitely preferable to complicating the delightfully simple little `Bunch` class with the semantically murky approaches shown in the previous paragraph.