Python: constrained containers
As it happens, I was playing with the del.icio.us API today because of reasons which I shall hopefully elaborate upon in the coming few days. While cooking up some code to interact with the API, I saw the need to model a basic del.icio.us post entity. For my needs, this entity wouldn't have to be much more than a dumb dictionary with keys like url, description, etc. So I started out that way but pretty soon I thought, wouldn't it be nice to be able to write post.url instead of post['url']? Further, wouldn't it be nice to constrain the keys in the dictionary to those required and prevent typo errors such as post['descrption'] instead of post['description']?
This seemed like the perfect opportunity to put into practice some of the stuff I'd learned about "new" style classes not too long ago. So I wrote the following class which implements the requirements laid out in the preceding paragraph. Since I'm just getting the hang of this stuff, please critique the code!
class Post(object): """Class to model a del.icio.us Post. It works like a struct/dict like object which limits keys to a retricted subset, i.e. those used in a del.icio.us post.""" __slots__ = ['description', 'url', 'extended', 'tags'] def __getitem__(self, key): if key in self.__slots__: return self.__getattribute__(key) else: raise KeyError def __setitem__(self, key, value): if key in self.__slots__: self.__setattr__(key, value) else: raise KeyError('Given key is not allowed in class %s'\ % self.__class__.__name__) def __contains__(self, key): try: self.__getitem__(key) except: return False return True # urllib.urlencode() just needs this beyond the basic stuff above def items(self): return [(k, self[k]) for k in self.__slots__ if k in self]
And here's the usage of the class.
>>> p = Post() >>> p.url Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: url >>> p.url = 'http://google.com' >>> p.url 'http://google.com' >>> p['url'] 'http://google.com' >>> p['desc'] Traceback (most recent call last): File "<stdin>", line 1, in <module> File "yummy.py", line 17, in __getitem__ raise KeyError KeyError >>> p['description'] = 'Google homepage' >>> p['description'] 'Google homepage' >>> p.items() [('description', 'Google homepage'), ('url', 'http://google.com')] >>> p.tags = 'search' >>> p.items() [('description', 'Google homepage'), ('url', 'http://google.com'), ('tags', 'search')] >>> 'extended' in p False >>> p.extended = 'homepage of the world' >>> p.items() [('description', 'Google homepage'), ('url', 'http://google.com'), ('extended', 'homepage of the world'), ('tags', 'search')] >>>
So, what am I doing wrong? :-)
Re: Python: constrained containers
HS wrote on Fri, 04 Jul 2008 18:47
No critiques. Just a couple of questions:
Why do you want to restrict the possible key values? It seems somewhat 'unpythonic' to do so.
Also, how about deriving your class from Dictionary? Wouldn't that also work?
Reply to this comment