while expression feature proposal

Tim Chase python.list at tim.thechases.com
Wed Oct 24 18:54:33 EDT 2012


On 10/24/12 17:26, Cameron Simpson wrote:
> On 24Oct2012 16:54, Tim Chase <python.list at tim.thechases.com> wrote:
> | On 10/24/12 16:34, Ian Kelly wrote:
> | > The idiomatic way to do this is:
> | > 
> | > while True:
> | >     VAR = EXPR
> | >     if not VAR:
> | >         break
> | >     BLOCK
> | 
> | It may be idiomatic, but that doesn't stop it from being pretty
> | ugly.
> 
> Yes, but more flexible because it accomodates loops where the natural
> place for the test is partway through the loop instead of right at the
> top, which is quite common.

Just like the "with" doesn't stop you from using a try/finally block
to do something similar, you can still write mid-loop exits as code
currently exists.  The proposed syntax just makes coming from other
languages easier to translate.

> | I must say I really like the parity of Dan's
> |   while EXPR as VAR:
> |      BLOCK
> | proposal with the "with" statement.
> 
> Well, it's nice. But usually EXPR will be a boolean.

I think the most common use-cases are boolean'ish.  The falsehood
means stop, but the truthiness value is not merely True.  The common
use-case I hit is the

  f = file('foo.bin')
  while True:
    data = f.read(CHUNK_SIZE)
    if not data: break
    process(data) #not just data=True

which tidily becomes

  while f.read(CHUNK_SIZE) as data:
    process(data)

>   m = re_FUNKYPATTERN.match(test_string)
>   if m:
>     do stuff with the results of the match, using "m"
> 
> If I could write this as:
> 
>   if re_FUNKYPATTERN.match(test_string) as m:
>     do stuff with the results of the match, using "m"

I'm -0 on this.  I don't like the pattern, but I'm not sure the "if
CONDITION as FOO" syntax yields nearly the functional & readable
improvement of "while THING as FOO".

> then some cascading parse decisions would feel a bit cleaner. Where I
> current have this:
> 
>   m = re_CONSTRUCT1.match(line)
>   if m:
>     ... handle construct 1 ...
>   else:
>     m = re_CONSTRUCT2.match(line)
>     if m:
>       ... handle construct 2 ...
>     else:
>       m = re_CONSTRUCT3.match(line)

For those, I often end up putting the regexps in a list and
iterating accordingly (which I have done multiple times):

  regexes = [
    re_one,
    re_two,
    re_three,
    ]
  for regex in regexes:
    m = regex.match(line)
    if m:
      handle(m)
      break
  else:
    doh()

Granted, it does expect that you want to handle the results
uniformly, but this could (usually) be mitigated with a dispatch
function as well

  regex_dispatches = [
    (re_one, handle1),
    (re_two, handle2),
    (re_three, handle3),
    ]
  for regex, fn in regex_dispatches:
    m = regex.match(line):
    if m:
      fn(m, extra_context)
      break
  else:
    doh()


> But I'm still -0 on it, because it supplants the glaringly obvious:
> 
>   m = ...
> 
> assignment with the far less in your face:
> 
>   possibly-long-expr as m

If it were replacing standard assignment, I'd be as off-the-charts
-1 as possible.  Yech.  But when cued by the "while" and
indentation, it's not quite so bad.  It still feels yucky™ in an
"if", but I find the improvement in the "while" is certainly worthwhile.


> With statements and except statements have concrete use cases for the
> "as" part that aren't doable without it, but the while/if...as form
> can always be written in the current convention.

The syntax for the with *could* have been something like

  with foo = file("foo.txt"):
    for line in foo:
      pass

but the "as" was chosen and I think it makes sense in the context.

-tkc

(To me, the "if CONDITION as VAR" feels much like the ternary
evaluation:

  x = foo if bar else baz

which made it into official syntax; I find the "while CONDITION as
VAR" much more readable/valuable in light of both)







More information about the Python-list mailing list