Often we want to just collect a bunch of stuff together, naming each item of the bunch; a dictionary's OK for that, but a small do-nothing class is even handier, and prettier to use.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Bunch:
def __init__(self, **kwds):
self.__dict__.update(kwds)
# that's it! Now, you can create a Bunch
# whenever you want to group a few variables:
point = Bunch(datum=y, squared=y*y, coord=x)
# and of course you can read/write the named
# attributes you just created, add others, del
# some of them, etc, etc:
if point.squared > threshold:
point.isok = 1
|
Dictionaries are fine for collecting a small bunch of stuff, each item with a name; however, when names are constants and to be used just like variables, the dictionary-access syntax ("if bunch['squared'] > threshold", etc) is not maximally clear; it takes VERY little effort to build a little class, as in the 'Bunch' example above, that will both ease the initialization task _and_ provide elegant attribute-access syntax ("if bunch.squared > threshold", etc).
It would not be hard to add __getitem__, __setitem__ and __delitem__ methods to allow attributes to also be accessed as bunch['squared'] etc -- they would just have to delegate to self.__dict__, e.g. via the handy functions getitem, setitem, delitem in module operator. This would mimic javascript use, where attributes and items are regularly confused; such unPythonic idioms, however, seem to be completely useless in Python. For occasional access to an attribute whose name is held in a variable (or otherwise runtime-computed), builtin functions getattr, setattr and delattr are perfectly adequate, and definitely preferable to complicating the delightfully-simple Bunch class.
Even shorter Bunch.
</pre></pre></pre>
Using a bunch as a dictionary. Quite simple extension of the original Bunch, just one extra line:
This has the added benefit that it can directly be printed and it shows its contents in interactive environments like ipython.
Using a bunch as a dictionary. Quite simple extension of the original Bunch, just one extra line:
This has the added benefit that it can directly be printed and it shows its contents in interactive environments like ipython.
One dictionary is better than two. How about just replacing self.__dict__ with self, since self is a dict?
Then any deletions, modifications, etc. are accessible via both the dict and attribute interfaces.
String representation. For debugging purposes, it's nice to have a meaningful string representation. This works for me:
Using dict functionality. You could simply do something like this, given the current functionality of dict (with kwd args etc.):
Of course, you won't get the right exceptions etcl., and simply setting __setattr__ the same way won't really work. But it seems to be about as simple as this recipe can get :)
Improvement to handle pickling. As written, pickling and unpickling such an object breaks the equivalence between self and self.__dict__. Adding the methods __getstate__ and __setstate__ used by the pickle protocol fixes this:
(Perhaps there's a better way to do this, but it seems to have the desired effect.)
Ugh; follow-up in wrong place. Apologies; that was supposed to be a comment on
"One dictionary is better than two", Graham Fawcett
CAUTION. this one leaks memory just try:
you need to stay away from circular references
CAUTION. this one leaks memory
just try:
... a = Bunch()
you need to stay away from circular references
CAUTION. as noted before - this leaks memory!
Is there an issue with using the type builtin for this ? If your use case is accessing **kw using dot notation then how about:
kw=type('bunch',(), kw)
Or, more closely following the 'utility helper' style of the original:
class Bunch(dict):
The above results in the below error. Is there a way to get the ease of use AND the ability to iterate through the values? ValueError: too many values to unpack
You are using iterkeys, which iterates over keys, not over key-value pairs. That’s what produces the ValueError: The first element from “fruit.iterkeys()” is not a sequence, so Python cannot unpack it to “k, v”.
Cheers