[Python-ideas] "While" suggestion
Terry Reedy
tjreedy at udel.edu
Tue Jul 8 20:16:11 CEST 2008
Talin wrote:
> I'm actually more interested in the "as" clause being added to "if"
> rather than "while". The specific use case I am thinking is matching
> regular expressions, like so:
>
> def match_token(s):
> # Assume we have regex's precompiled for the various tokens:
> if re_comment.match(s) as m:
> # Do something with m
> process(TOK_COMMENT, m.group(1))
> elif re_ident.match(s) as m:
> # Do something with m
> process(TOK_IDENT, m.group(1))
> elif re_integer.match(s) as m:
> # Do something with m
> process(TOK_INT, m.group(1))
> elif re_float.match(s) as m:
> # Do something with m
> process(TOK_COMMENT, m.group(1))
> elif re_string.match(s) as m:
> # Do something with m
> process(TOK_STRING, m.group(1))
> else:
> raise InvalidTokenError(s)
>
> In other words, the general design pattern is one where you have a
> series of tests, where each test can return either None, or an object
> that you want to examine further.
One of the things I do not like above is the repetition of the
assignment target, and statement ends, where it is a little hard to see
if it is spelled the same each time. I think it would be more
productive to work on adding to the stdlib a standardized store-and-test
class -- something like what others have posted on c.l.p. In the below,
I factored out the null test value(s) from the repeated if tests and
added it to the pocket instance as a nulls test attribute.
def pocket():
def __init__(self, nulls):
if type(nul;s) != tuple or nulls == ():
nulls = (nulls,)
self.nulls = nulls
def __call__(self, value):
self.value = value
return self
def __bool__(self)
return not (self.value in self.nulls)
then
def match_token(s):
# Assume we have regex's precompiled for the various tokens:
p = pocket(None) # None from above, I don't know match return
if p(re_comment.match(s)):
# Do something with p.value
process(TOK_COMMENT, p.value.group(1))
elif p(re_ident.match(s)):
# Do something with p.value
process(TOK_IDENT, p.value.group(1))
elif p(re_integer.match(s)):
# etc
Pocket could be used for the while case, but I will not show that
because I strongly feel 'for item in iteratot' is the proper idiom.
Your specific example is so regular that it also could be written
(better in my opinion) as a for loop by separating what varies from what
does not:
match_tok = (
(re_comment, TOK_COMMENT),
(re_indent, TOK_INDENT),
...
(re_string, TOK_STRING),
)
# if <re_x> is actually re.compile(x), then tokens get bundled with
# matchers as they are compiled. This strikes me as good.
for matcher,tok in match_tok:
m = matcher.match(s)
if m:
process(tok, m.group(1)
break
else:
raise InvalidTokenError(s)
Notice how nicely Python's rather unique for-else clause handles the
default case.
Terry Jan Reedy
More information about the Python-ideas
mailing list