trap attributeError from inside a dict ?

Peter Otten __peter__ at web.de
Wed Mar 10 11:04:51 CET 2004


GrelEns wrote:

> hello,
> 
> i would like if this behaviour can be obtained from python : trap an
> attributeError from inside a subclassing dict class... (here is a silly
> examples to explain my question)
> 
> class Test(dict):
>  """subclassing a dict and each key will permit access to a tuple of fized
> size"""
>  def __init__(self):
>   pass
>  def load(self, adict):
>   """actually it will be done from a text file with fixed size fields,
>   each
> tuple will have the same size"""
>   for k in adict:
>    self[k] = tuple(adict[k])
> 
> t = Test()
> t.load({1: ('a', 'aa'), 2: ('(b', 'bb')})
> 
> here is what i would have :
>>>> t[1].get('first')
> 'a'
> 
> without having to define tuple as an object or subclassing tuple, of
> course now i had :
>>>> t[1].get('first')
> 
> Traceback (most recent call last):
>   File "<pyshell#15>", line 1, in -toplevel-
>     t['A'].get('first')
> AttributeError: 'tuple' object has no attribute 'get'
> 
> is it possible ?
> 
> btw my question is something like is there a way from inside Test code to
> say to python that when it first get t[1] it should not go further, trap
> the things one ask to do on t[key] and then calling a function such as
> 
> (inside Test)
>     def __get(self, key, readable):
>         mapping = {'first' : 1, 'second' : 2}
>         return self[key][mapping[readable]]
> 
> (maybe it is a silly design...but i need this because i do want some kind
> of readable object access without having to create all these objects)

Here's one way to do it:
 
>>> class Dict(dict):
...     translate = {"first": 0, "second": 1}
...     def __getitem__(self, key):
...             value = dict.__getitem__(self, key[0])
...             return value[self.translate[key[1]]]
...
>>> d = Dict([(1,("a", "aa")), (2, ("b", "bb"))])
>>> d[1, "first"]
'a'
>>> d[2, "second"]
'bb'

Here's another:

>>> class Dict(dict):
...     def __getitem__(self, key):
...             return Wrap(dict.__getitem__(self, key))
...
>>> class Wrap(object):
...     def __init__(self, data): self.data = data
...     first = property(lambda self: self.data[0])
...     second = property(lambda self: self.data[1])
...
>>> d = Dict([(1,("a", "aa")), (2, ("b", "bb"))])
>>> d[1].first
'a'
>>> d[2].second
'bb'
>>>

Note that you might end with *more* objects as every call to __getitem__()
creates a new Wrap instance. A cache could help, but if you did it properly
with a custom class for the values the problem wouldn't arise. 
Personally, I would put custom objects into a normal dictionary instead of
playing one of these tricks.

Peter




More information about the Python-list mailing list