Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Python (http://www.velocityreviews.com/forums/f43-python.html)
-   -   Arent these snippets equivalent? (http://www.velocityreviews.com/forums/t956851-arent-these-snippets-equivalent.html)

Coolgg 01-23-2013 09:56 PM

Arent these snippets equivalent?
 
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/pyth...n-loop-control


John Gordon 01-23-2013 10:06 PM

Re: Arent these snippets equivalent?
 
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"


Chris Angelico 01-23-2013 10:13 PM

Re: Arent these snippets equivalent?
 
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

Roy Smith 01-23-2013 10:47 PM

Re: Arent these snippets equivalent?
 
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".

Evan Driscoll 01-23-2013 11:17 PM

Re: Arent these snippets equivalent?
 
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/pyth...n-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


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJRAG+jAAoJEAOzoR8eZTzgfqcH/jkzORjA64IPtyrPTPn61Owh
Ng7xsU4pNxUKiJR0qFZXfmG5XTIgmKqBq9+so4ZcuL0c1xqlKN CTbFj+xngd20pZ
av3UT65cqxnmaw8E5FNQliUFCm+d07ewMoFRyEM0c8J7xMTN8q 3mo5WEC9XfQIJ9
km59y2CV363Cs7DA5nAKTTn/sEUCmYogybnLooz6PUQInse1MBmRveuvEr6z7g/Y
o5Wb3PxNWKM1UILEltaFOFe3TXqnUfOfWyNDqUrbATDIeMWsaA 8ykcUQb0YzPMN7
IeQG5xz/myalNuMgQpUh5r1LAAcwUHP5ThG2K1PCjXodrnRN4Km8jABPZK AMuzI=
=9uJn
-----END PGP SIGNATURE-----


Chris Angelico 01-23-2013 11:29 PM

Re: Arent these snippets equivalent?
 
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

Tim Chase 01-23-2013 11:29 PM

Re: Arent these snippets equivalent?
 
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




Terry Reedy 01-24-2013 02:38 AM

Re: Arent these snippets equivalent?
 
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


Coolgg 01-24-2013 05:01 AM

Re: Arent these snippets equivalent?
 
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.

Coolgg 01-24-2013 05:01 AM

Re: Arent these snippets equivalent?
 
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.


All times are GMT. The time now is 05:53 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.