assignment expression peeve

David C. Fox davidcfox at post.harvard.edu
Wed Oct 15 10:11:54 EDT 2003


Paul Rubin wrote:
> OK, I want to scan a file for lines matching a certain regexp.  I'd
> like to use an assignment expression, like
> 
>    for line in file:
>       if (g := re.match(pat, line)):
>          croggle(g.group(1))
> 
> Since there are no assignment expressions in Python, I have to use a
> temp var.  That's a little more messy, but bearable:
> 
>    for line in file:
>       g = re.match(pat, line)
>       if g:
>          croggle(g.group(1))
> 
> It gets annoying when there are 4 different regexps that the line
> might match, and I want to do something different depending on which
> one matches.  That's not that uncommon a text scanning situation.
> With assignment expressions, it's a very natural if/elif chain:
> 
>    for line in file:
>      if g := re.match(pat1, line):
>         croggle(g.group(1), 17)
>      elif g := re.match(pat2, line):
>         x = mugwump(g.group(3))
>         y = wumpus(g.group(2))
>         return defenestrate(x, y+3)
>      elif g := re.match(pat3, line):
>         # do something completely different with groups of g
>      elif g := re.match(pat4, line):
>         # more of the same
> 
> Without assigment expressions, it gets unspeakably ugly.  You have to
> use a deeply nested if/else if sequence where you match the regexp and
> test the result on 2 separate lines at each branch, or reorganize the
> code to use some kind of dispatch table (good if there's a lot more
> than 4 regexps, but overkill for just 4), or whatever.  I ended up
> creating a special class instance just to match a regexp and remember
> the result, so I could write in the if/elif style.
> 
> This kind of regexp matching is a common pattern and I keep wanting
> assignment expressions whenever I code it, and end up crocking up some
> silly workaround.

I like Alex's suggestion, but if you really want to do this generically, 
and not just for re.match, you can create a generic proxy object 
something like this:

class SetTo:
     def setto(self, value):
         self.__dict__['value'] = value
         return value
     def __getattr__(self, name):
         return getattr(self.value, name)
     def __setattr__(self, name, value):
         return setattr(self.value, name, value)

Then your example above can be rewritten as

     g = SetTo()
     for line in file:
         if g.setto(re.match(pat1, line)):
             croggle(g.group(1), 17)
         elif g.setto(re.match(pat2, line)):
             x = mugwump(g.group(3))
             y = wumpus(g.group(2))
             return defenestrate(x, y+3)
         elif g.setto(re.match(pat3, line)):
             # do something completely different with groups of g
         elif g.setto(re.match(pat4, line)):
             # more of the same

David





More information about the Python-list mailing list