Newbie question about __getattr__ and __setattr__

Eric Jacobs x at x.x
Tue Oct 12 20:17:46 EDT 1999


Felix Thibault wrote:
> 
> On Sat, 09 Oct 1999 01:24:38 -0400, Eric Jacobs <x at x.x> wrote:
> >
> > A couple of things going on here. First, you want to deal with
> > __getitem__ and __setitem__ -- those deal with the [] subscript
> > operator -- rather than __getattr__ and __setattr__ that deal
> > with the . attribute operator.
> >
> > The syntax that you want to write the assignment is supported
> > by the interpreter by default; you don't need to change
> > anything for that. The only catch is that the first two layers
> > of dictionaries need to exist beforehand. So if you had
> >
> >    i = {1: {2: {}}}
> >    i[1][2][3] = 4
> >
> > then i would be {1: {2: {3: 4}}} as you'd expect.
> [snip]
> > So if you want that assignment to work when the sub-
> > dictionaries aren't predefined, you can have your
> > __getitem__ always create new dictionaries. That's
> > fairly simple, just add a method:
> >
> >       def __getitem__(s, k):
> >               if k not in s.keys():
> >                       s[k] = Nester({})
> >               return s.data[k]
> >
> > Be sure to mention the s.data[k] and not just s[k], or
> > you'll end up in an infinite loop. Here, if the key is not
> > found, we generate a new custom Nester object, so that it
> > works for more than one level. In fact, because there's no
> > limit placed here, this will work for any number of nested
> > levels:
> > i['a']['b']['c']['d']['e'][...
> >
> > The disadvantage is that reading a missing value will
> > result in a new empty dictionary being created and returned!
> > So unless you want to be really careful and write a clean-
> > up routine which can handle this, you're going to have a
> > bunch of extra empty dictionaries floating around. You will
> > also never get KeyError with this simple method.
> 
> So I would need to, for example, make a function that checks
> the value of a key and deletes it and raises a KeyError if it's {}, and
> then call that function after every read ?

That would be one way to do it. That's assuming, of course, that
you don't want to actually store {} in the dictionary. Another way
that would work if you know that number of nested levels that are
supposed to be in the dictionary would be to count down that
number with every __getitem__. So, you might do: (from the
example __getitem__ above)

			  if s.l > 0:
	                       	s[k] = Nester({}, s.l-1)
			  else:
				s[k] = {}

In this case when l (the current level) gets down to 0, it
will generate a regular dictionary rather than the one using
the Nester wrapper. In this case, the normal dictionary code
will raise KeyError when a key is not found. This will also
not generate extra {}'s that you have to delete, but it will
lock you into using a certain number of levels.




More information about the Python-list mailing list