Nested string substitutions

holger krekel pyth at devel.trillke.net
Mon Dec 30 06:34:34 EST 2002


Mike Meyer wrote:
> [Apologies for digging out an old thread, but I spent the holiday with
> my sons...]

very much appreciated, especially since i bored away the Lotus Eater
already :-)  

> holger krekel <pyth at devel.trillke.net> writes:
> > Lulu of the Lotus-Eaters wrote:
> > > |def expand(d):
> > > |    while filter(lambda (n, v): d.__setitem__(n,
> > > |        reduce(lambda x,k: x.replace(k, d[k]), d, v)
> > > |    ) or v!=d[n], d.items()): pass
> > > Wow!  Who ever said Perl was hard to read :-).  How long did that take
> > > to think of, Holger?
> > I produced a *readable* versions in 1-2 hours.  Using all the ideas
> > from these versions the above snippet took around 20 minutes.  Maybe
> > i mistake your original mail (where you mentioned one or two lines). 
> 
> That use of reduce is *very* cool. I think I missed something in the
> docs, as I didn't realize dictionaries would turn into a sequence of
> their keys.

Actually some people think that iterating over a dict (for i in d:...)
should yield items.  It's still needs conscious effort on my part 
to keep in mind that iteration over a dict just yields keys.  My gut
feeling has it that "canonical" iteration should yield everything of a
container not just some random part. 

> > class subst_dict(dict):
> >     def __call__(self, string, key=None):
> >         """replace occurences of 'key' in 'string' with dict-value.
> > 
> >            for a None key all keys of the dict are applied
> >            sequentially. If a key is not in the dict the
> >            string is returned unmodified.
> >         """
> >         if key is None:
> >             return reduce(self, self, string)
> >         newstring = string.replace(key, self.get(key,key))
> >         if newstring != string:
> >             return self(newstring)
> >         return newstring
> 
> Making it an ancester of the dict class feels very pythonic. The tail
> recursion doesn't. Might I suggest:
> 
>    def __call__(self, string):
>       previous = ""
>       while previous != string:
>          previous = string
>          string = reduce(lambda x, k: x.replace(k, self[k]), self, string)
> 
> You probably went through this in your conversion. I find that once I
> got my head around the reduce, having the string replacement in an
> embedded lambda is easier to understand than having __call__ serve
> double duty. 

yes, thanks! This combines our two solutions in a very nice way.  
It should also be the fastest of all presented solutions so far. 
I notice that i use recursion too easily, sometimes.  

> If you really want to keep the string with key replacment
> functionality, it could be done as a separate method, and then that
> method used in the reduce call.

no need.  your change is fine. 

cheers,

    holger




More information about the Python-list mailing list