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