magical expanding hash

James Stroud jstroud at ucla.edu
Tue Jan 17 21:28:02 EST 2006


braver wrote:
> Thanks, James!  This is really helpful.
> 
> : It would take a lot of coding to make that << work right. Better is
> the pythonic
> :
> : m[key] = [value]
> :
> : Its really only one more keystroke than
> :
> : m[key] << value
> 
> But it's only for the first element, right?  I'd have to say
> meh[key1]...[keyN].append(elem2) after that, while I want an operator
> to look the same.

Yes, being explicit is only for the first element with the "<<". If you 
use the lshiftinglist I provided, you could easily do


class lshiftinglist(list):
   def __lshift__(self, value):
     list.append(self, value)

class meh(dict):
   def __getitem__(self, item):
     return dict.setdefault(self, item, meh())
   def __getattr__(self, attr):
     return self.ga(attr)
   def __lshift__(self, value):
     print "You are thinking of '%s'." % value
   def __iadd__(self, other):
     # don't try this on a populated meh!!!!!
     return other

m = meh()

m['fred'] = lshiftinglist([18])
m['fred'] << 25
m['barney'] += 1
m['barney'] += 1

print m  # {'barney': 2, 'fred': [18, 25]}


And so-on. More pythonic, of course is

m['fred'] = [18]
m['key'].append(25)
m['barney'] = 1
m['barney'] += 1


Now the reason "m['barney'] += 1" works in the former is becasue "+=" 
actually returns a value to which the name on the left gets re-assigned. 
"<<" does not work this way, so it can't be done as easily.

You might want to make a named method that thinks for you. The resulting 
  code is less terse but more clear (i.e. pythonic):


def meh_append(ameh, key, value):
   if not ameh.has_key(key):
     ameh[key] = [value]
   else:
     ameh[key].append(value)

def meh_addleaf(ameh, key, value={}):
   if value == {}:
     ameh[key] = {}
   else:
     ameh[key] = value

m = meh()

meh_addleaf(m['bob'], 'carol', None)
meh_append(m['ted'], 'alice', 14)
meh_append(m, 'fred', 1)
meh_append(m, 'fred', 2)

print m # {'bob': {'carol': None},
         #  'ted': {'alice': [14]}, 'fred': [1, 2]}

But now its getting very pythonic. And the only magic we need is the 
original __getattr__ modification, which we could find a way of 
eliminating if we tried.

James



More information about the Python-list mailing list