Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #37506 > unrolled thread
| Started by | Coolgg <gauravj123@gmail.com> |
|---|---|
| First post | 2013-01-23 13:56 -0800 |
| Last post | 2013-01-23 17:17 -0600 |
| Articles | 10 — 7 participants |
Back to article view | Back to comp.lang.python
Arent these snippets equivalent? Coolgg <gauravj123@gmail.com> - 2013-01-23 13:56 -0800
Re: Arent these snippets equivalent? John Gordon <gordon@panix.com> - 2013-01-23 22:06 +0000
Re: Arent these snippets equivalent? Chris Angelico <rosuav@gmail.com> - 2013-01-24 09:13 +1100
Re: Arent these snippets equivalent? Roy Smith <roy@panix.com> - 2013-01-23 17:47 -0500
Re: Arent these snippets equivalent? Tim Chase <python.list@tim.thechases.com> - 2013-01-23 17:29 -0600
Re: Arent these snippets equivalent? Chris Angelico <rosuav@gmail.com> - 2013-01-24 10:29 +1100
Re: Arent these snippets equivalent? Terry Reedy <tjreedy@udel.edu> - 2013-01-23 21:38 -0500
Re: Arent these snippets equivalent? Coolgg <gauravj123@gmail.com> - 2013-01-23 21:01 -0800
Re: Arent these snippets equivalent? Coolgg <gauravj123@gmail.com> - 2013-01-23 21:01 -0800
Re: Arent these snippets equivalent? Evan Driscoll <driscoll@cs.wisc.edu> - 2013-01-23 17:17 -0600
| From | Coolgg <gauravj123@gmail.com> |
|---|---|
| Date | 2013-01-23 13:56 -0800 |
| Subject | Arent these snippets equivalent? |
| Message-ID | <d7191cec-d963-42c8-90ba-db6d1359ceeb@googlegroups.com> |
Is this:
while True:
data = fp.read(4096)
if not data:
break
...
not equivalent to this:
data = fp.read (4096)
while data:
...{handle the chunk here}
data = fp.read (4096)
Heres the article that sparked this question:
http://wordaligned.org/articles/pythons-lesser-known-loop-control
[toc] | [next] | [standalone]
| From | John Gordon <gordon@panix.com> |
|---|---|
| Date | 2013-01-23 22:06 +0000 |
| Message-ID | <kdpmsv$ec6$1@reader1.panix.com> |
| In reply to | #37506 |
In <d7191cec-d963-42c8-90ba-db6d1359ceeb@googlegroups.com> Coolgg <gauravj123@gmail.com> writes:
> Is this:
> while True:
> data = fp.read(4096)
> if not data:
> break
> ...
> not equivalent to this:
> data = fp.read (4096)
> while data:
> ...{handle the chunk here}
> data = fp.read (4096)
It looks equivalent to me (in terms of control flow).
But in the second example the fp.read() statement is duplicated, which is
undesirable. It would be all too easy for a maintenance programmer to go
into the code a year from now and change the first one but miss the second
one.
--
John Gordon A is for Amy, who fell down the stairs
gordon@panix.com B is for Basil, assaulted by bears
-- Edward Gorey, "The Gashlycrumb Tinies"
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-01-24 09:13 +1100 |
| Message-ID | <mailman.923.1358979203.2939.python-list@python.org> |
| In reply to | #37506 |
On Thu, Jan 24, 2013 at 8:56 AM, Coolgg <gauravj123@gmail.com> wrote:
> Is this:
>
> while True:
> data = fp.read(4096)
> if not data:
> break
> ...
>
> not equivalent to this:
>
> data = fp.read (4096)
> while data:
> ...{handle the chunk here}
> data = fp.read (4096)
They should do the same thing, but there's one critical difference in
the second: Edits to something that's really part of the loop now have
to be done twice, at the bottom of the loop and *before the loop*.
It's a violation of the principle Don't Repeat Yourself.
Personally, I'd much rather have a 'while' condition that does
assignment, but that's something Python's unlikely ever to do.
There've been various proposals to make that possible, but ultimately
the only way to make that work is for assignment to be an expression,
which is right up there alongside braces defining blocks.
(Wonder when we'll see "from __future__ import assignment_expression"
implemented...)
The 'break' method is the most common. Assuming you're doing something
as simple as the above, with a single function call and a clear
condition, it's pretty readable. Compare:
while (data = fp.read(4096))
{
... imagine about 20 lines here
}
and
while True:
data = fp.read(4096)
if not data: break
... imagine those same 20 lines, ported to Python
The critical parts of your while loop are in those first three lines.
It's the same goal as a C-style for loop - you can see everything you
need right up there at the loop header. All you have to do is
understand that the "loop header" is three lines long now.
With the second form of the loop, though, the loop header is down at
the bottom of the loop too. It's less clear. Granted, this might be
how a compiler lays it out in memory, but programmers shouldn't have
to read it that way.
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2013-01-23 17:47 -0500 |
| Message-ID | <roy-3DE6E9.17475523012013@news.panix.com> |
| In reply to | #37509 |
In article <mailman.923.1358979203.2939.python-list@python.org>,
Chris Angelico <rosuav@gmail.com> wrote:
> Personally, I'd much rather have a 'while' condition that does
> assignment, but that's something Python's unlikely ever to do.
> There've been various proposals to make that possible, but ultimately
> the only way to make that work is for assignment to be an expression,
> which is right up there alongside braces defining blocks.
while getchar() as c:
putchar(c)
That would give people (including me) the use case they're after most of
the time (call a function, assign the return value, and test it). It's
way less klunky than:
while True:
c = getchar()
if c:
break
putchar()
It wouldn't require assignment as an expression, or braces, or any new
keywords. It would also be quite analogous to
try:
blah()
except BogusThing as ex:
whatever()
in both cases, the effect is "perform some action, grab a value which
resulted from that, and if it passes some test, make it available in the
next block bound to a name".
[toc] | [prev] | [next] | [standalone]
| From | Tim Chase <python.list@tim.thechases.com> |
|---|---|
| Date | 2013-01-23 17:29 -0600 |
| Message-ID | <mailman.932.1358983703.2939.python-list@python.org> |
| In reply to | #37513 |
On 01/23/13 16:47, Roy Smith wrote:
> while getchar() as c:
> putchar(c)
>
> That would give people (including me) the use case they're after most of
> the time (call a function, assign the return value, and test it). It's
> way less klunky than:
>
> while True:
> c = getchar()
> if c:
# I presume you mean "if not c:" here.
> break
> putchar()
I was a pretty strong advocate early in one of these long threads,
and for the simple cases, it's some attractive syntactic sugar.
However, I found that it quickly blossomed into a lot of really ugly
edge cases (multiple tests, multiple results, checking for "is None"
vs. false'ness or some other condition such as "< 0"). I found that
it was pretty easy to create a generator-wrapper for this:
def getter(fn):
while True:
val = fn()
if not val: break
yield val
# DB example
cursor = conn.cursor()
for row in getter(lambda: cursor.fetchmany()):
do_something(row)
# your getchar example
for c in getter(getchar):
do_something_else(c)
This allowed me to have both the readability and customized tests
(and the ability to return multiple values). It could be expanded with
def getter(fn, is_at_end=lambda v: not v):
while True:
val = fn()
if is_at_end(val): break
yield val
which would even allow you to do things like
for line in getter(file("foo.txt"), lambda s: s.find("xxx") < 0):
print "This line has 'xxx' in it:"
print line
and those felt a lot more pythonic than any of the proposals I saw
on the list.
-tkc
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-01-24 10:29 +1100 |
| Message-ID | <mailman.933.1358983756.2939.python-list@python.org> |
| In reply to | #37513 |
On Thu, Jan 24, 2013 at 9:47 AM, Roy Smith <roy@panix.com> wrote: > while getchar() as c: > putchar(c) > > That would give people (including me) the use case they're after most of > the time (call a function, assign the return value, and test it). It's > way less klunky than: > > while True: > c = getchar() > if c: > break > putchar() > > It wouldn't require assignment as an expression, or braces, or any new > keywords. I believe this was discussed recently (on python-ideas?). It's nice in its simplest form, but doesn't cover all possibilities. My point about braces was that, like assignment-expressions, it's a feature that Python will not be implementing. Fundamentally against the "push" of the language. If you want C, you know where to get it. (There are other options, of course; ECMAScript and Pike come to mind. But you know what I mean.) ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2013-01-23 21:38 -0500 |
| Message-ID | <mailman.939.1358995175.2939.python-list@python.org> |
| In reply to | #37513 |
On 1/23/2013 6:29 PM, Tim Chase wrote:
> On 01/23/13 16:47, Roy Smith wrote:
>> while getchar() as c:
>> putchar(c)
>>
>> That would give people (including me) the use case they're after most of
>> the time (call a function, assign the return value, and test it). It's
>> way less klunky than:
>>
>> while True:
>> c = getchar()
>> if c:
> # I presume you mean "if not c:" here.
>> break
>> putchar()
>
> I was a pretty strong advocate early in one of these long threads, and
> for the simple cases, it's some attractive syntactic sugar. However, I
> found that it quickly blossomed into a lot of really ugly edge cases
> (multiple tests, multiple results, checking for "is None" vs. false'ness
> or some other condition such as "< 0"). I found that it was pretty easy
> to create a generator-wrapper for this:
>
> def getter(fn):
> while True:
> val = fn()
> if not val: break
> yield val
>
> # DB example
> cursor = conn.cursor()
> for row in getter(lambda: cursor.fetchmany()):
> do_something(row)
>
> # your getchar example
> for c in getter(getchar):
> do_something_else(c)
>
> This allowed me to have both the readability and customized tests (and
> the ability to return multiple values). It could be expanded with
>
> def getter(fn, is_at_end=lambda v: not v):
> while True:
> val = fn()
> if is_at_end(val): break
> yield val
>
> which would even allow you to do things like
>
> for line in getter(file("foo.txt"), lambda s: s.find("xxx") < 0):
> print "This line has 'xxx' in it:"
> print line
>
> and those felt a lot more pythonic than any of the proposals I saw on
> the list.
I agree. To me, the beauty of iterators and for loops is that they
separate production of the items of a collection from the processing of
the same items. The two processes are often quite independent, and
separating them clearly allows us to mix and match. For instance, when
summing numbers, the internal details of producing the numbers does not
matter.
--
Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
| From | Coolgg <gauravj123@gmail.com> |
|---|---|
| Date | 2013-01-23 21:01 -0800 |
| Message-ID | <a440e905-cf6b-486a-89e9-164793ef076d@googlegroups.com> |
| In reply to | #37530 |
On Wednesday, January 23, 2013 6:38:54 PM UTC-8, Terry Reedy wrote:
> On 1/23/2013 6:29 PM, Tim Chase wrote:
>
> > On 01/23/13 16:47, Roy Smith wrote:
>
> >> while getchar() as c:
>
> >> putchar(c)
>
> >>
>
> >> That would give people (including me) the use case they're after most of
>
> >> the time (call a function, assign the return value, and test it). It's
>
> >> way less klunky than:
>
> >>
>
> >> while True:
>
> >> c = getchar()
>
> >> if c:
>
> > # I presume you mean "if not c:" here.
>
> >> break
>
> >> putchar()
>
> >
>
> > I was a pretty strong advocate early in one of these long threads, and
>
> > for the simple cases, it's some attractive syntactic sugar. However, I
>
> > found that it quickly blossomed into a lot of really ugly edge cases
>
> > (multiple tests, multiple results, checking for "is None" vs. false'ness
>
> > or some other condition such as "< 0"). I found that it was pretty easy
>
> > to create a generator-wrapper for this:
>
> >
>
> > def getter(fn):
>
> > while True:
>
> > val = fn()
>
> > if not val: break
>
> > yield val
>
> >
>
> > # DB example
>
> > cursor = conn.cursor()
>
> > for row in getter(lambda: cursor.fetchmany()):
>
> > do_something(row)
>
> >
>
> > # your getchar example
>
> > for c in getter(getchar):
>
> > do_something_else(c)
>
> >
>
> > This allowed me to have both the readability and customized tests (and
>
> > the ability to return multiple values). It could be expanded with
>
> >
>
> > def getter(fn, is_at_end=lambda v: not v):
>
> > while True:
>
> > val = fn()
>
> > if is_at_end(val): break
>
> > yield val
>
> >
>
> > which would even allow you to do things like
>
> >
>
> > for line in getter(file("foo.txt"), lambda s: s.find("xxx") < 0):
>
> > print "This line has 'xxx' in it:"
>
> > print line
>
> >
>
> > and those felt a lot more pythonic than any of the proposals I saw on
>
> > the list.
>
>
>
> I agree. To me, the beauty of iterators and for loops is that they
>
> separate production of the items of a collection from the processing of
>
> the same items. The two processes are often quite independent, and
>
> separating them clearly allows us to mix and match. For instance, when
>
> summing numbers, the internal details of producing the numbers does not
>
> matter.
>
>
>
> --
>
> Terry Jan Reedy
Thanks for all the perspectives everyone. I was just curious about the functional equivalence and I got what I needed.
[toc] | [prev] | [next] | [standalone]
| From | Coolgg <gauravj123@gmail.com> |
|---|---|
| Date | 2013-01-23 21:01 -0800 |
| Message-ID | <mailman.944.1359006419.2939.python-list@python.org> |
| In reply to | #37530 |
On Wednesday, January 23, 2013 6:38:54 PM UTC-8, Terry Reedy wrote:
> On 1/23/2013 6:29 PM, Tim Chase wrote:
>
> > On 01/23/13 16:47, Roy Smith wrote:
>
> >> while getchar() as c:
>
> >> putchar(c)
>
> >>
>
> >> That would give people (including me) the use case they're after most of
>
> >> the time (call a function, assign the return value, and test it). It's
>
> >> way less klunky than:
>
> >>
>
> >> while True:
>
> >> c = getchar()
>
> >> if c:
>
> > # I presume you mean "if not c:" here.
>
> >> break
>
> >> putchar()
>
> >
>
> > I was a pretty strong advocate early in one of these long threads, and
>
> > for the simple cases, it's some attractive syntactic sugar. However, I
>
> > found that it quickly blossomed into a lot of really ugly edge cases
>
> > (multiple tests, multiple results, checking for "is None" vs. false'ness
>
> > or some other condition such as "< 0"). I found that it was pretty easy
>
> > to create a generator-wrapper for this:
>
> >
>
> > def getter(fn):
>
> > while True:
>
> > val = fn()
>
> > if not val: break
>
> > yield val
>
> >
>
> > # DB example
>
> > cursor = conn.cursor()
>
> > for row in getter(lambda: cursor.fetchmany()):
>
> > do_something(row)
>
> >
>
> > # your getchar example
>
> > for c in getter(getchar):
>
> > do_something_else(c)
>
> >
>
> > This allowed me to have both the readability and customized tests (and
>
> > the ability to return multiple values). It could be expanded with
>
> >
>
> > def getter(fn, is_at_end=lambda v: not v):
>
> > while True:
>
> > val = fn()
>
> > if is_at_end(val): break
>
> > yield val
>
> >
>
> > which would even allow you to do things like
>
> >
>
> > for line in getter(file("foo.txt"), lambda s: s.find("xxx") < 0):
>
> > print "This line has 'xxx' in it:"
>
> > print line
>
> >
>
> > and those felt a lot more pythonic than any of the proposals I saw on
>
> > the list.
>
>
>
> I agree. To me, the beauty of iterators and for loops is that they
>
> separate production of the items of a collection from the processing of
>
> the same items. The two processes are often quite independent, and
>
> separating them clearly allows us to mix and match. For instance, when
>
> summing numbers, the internal details of producing the numbers does not
>
> matter.
>
>
>
> --
>
> Terry Jan Reedy
Thanks for all the perspectives everyone. I was just curious about the functional equivalence and I got what I needed.
[toc] | [prev] | [next] | [standalone]
| From | Evan Driscoll <driscoll@cs.wisc.edu> |
|---|---|
| Date | 2013-01-23 17:17 -0600 |
| Message-ID | <mailman.929.1358983138.2939.python-list@python.org> |
| In reply to | #37506 |
[Multipart message — attachments visible in raw view] — view raw
On 01/23/2013 03:56 PM, Coolgg wrote:
> Is this:
>
> while True:
> data = fp.read(4096)
> if not data:
> break
> ...
>
> not equivalent to this:
>
> data = fp.read (4096)
> while data:
> ...{handle the chunk here}
> data = fp.read (4096)
>
> Heres the article that sparked this question:
> http://wordaligned.org/articles/pythons-lesser-known-loop-control
There is at least one potentially-critical difference: what happens if
there is a 'continue' statement in the "..." part. The upper loop will
set data again, while the lower one will not.
So if what you mean is "are they equivalent no matter what legal Python
code you put in the ...", no, they aren't.
Evan
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web