This post originated from an RSS feed registered with Python Buzz
by Ben Last.
Original Post: Bags and Objects
Feed Title: The Law Of Unintended Consequences
Feed URL: http://benlast.livejournal.com/data/rss
Feed Description: The Law Of Unintended Consequences
Someone (who remained anonymous) was kind enough to point out, following my last entry, that there's an equivalent to Bag built into Zope; the Products.PythonScripts.standard.Object class[1]. It, too, initializes from keyword parameters and also emulates dict semantics (which, interestingly enough, I'd added to Bag before reading the comment). Where I ran into problems in trying it out is with iteration. There's debug code in my Zope site that does something like:
<span tal:repeat="key myBagOfStuff">
<p>Key is <b tal:content="key">key</b>, value is <b tal:content="myBagOfStuff/?key">value</b>
</span>
to iterate over the keys. Objects can't do that, nor can they support the more basic iteration style:
<span tal:repeat="item myBagOfStuff">
<p>Item is <b tal:content="item">item</b>
</span>
But as long as you don't need iteration (and given a decent implementation of __str__, I don't need to), Object is a Good Thing, not least because it's usable from within PythonScripts where classes can't be defined.
Anyway, I still found it interesting to build something that (when completed) had keyword initialization, dict-semantics emulation[2] and key iteration, so here it is.
class Bag(object):
def __init__(self, **kw):
"""Initialise, and set attributes from all keyword arguments."""
self.__allow_access_to_unprotected_subobjects__=1
self.__members=[]
for k in kw.keys():
setattr(self,k,kw[k])
self.__remember(k)
def __remember(self, k):
"""Add k to the list of explicitly set values."""
if not k in self.__members:
self.__members.append(k)
def __getitem__(self, key):
"""Equivalent of dict access by key."""
try:
return getattr(self, key)
except AttributeError:
raise KeyError, key
def __setitem__(self, key, value):
setattr(self, key, value)
self.__remember(key)
def has_key(self, key):
return hasattr(self, key)
def keys(self):
return self.__members
def iterkeys(self):
return self.__members
def __iter__(self):
return iter(self.__members)
def __str__(self):
"""Describe only those attributes explicitly set."""
s = ""
for x in self.__members:
v = getattr(self, x)
if s: s+=", "
s += "%s: %s" % (x, `v`)
return s
[1] It's not actually a class, it's a method Object() that returns objects of class _Object so that Zope security paranoia rules can be observed. Just to be clear :) [2] As much as I needed it, anyway - there's no iteritems or itervalues support.