Arent these snippets equivalent?

Discussion in 'Python' started by Coolgg, Jan 23, 2013.

  1. Coolgg

    Coolgg Guest

    Coolgg, Jan 23, 2013
    #1
    1. Advertising

  2. Coolgg

    John Gordon Guest

    In <> Coolgg <> 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
    B is for Basil, assaulted by bears
    -- Edward Gorey, "The Gashlycrumb Tinies"
     
    John Gordon, Jan 23, 2013
    #2
    1. Advertising

  3. On Thu, Jan 24, 2013 at 8:56 AM, 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)


    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
     
    Chris Angelico, Jan 23, 2013
    #3
  4. Coolgg

    Roy Smith Guest

    In article <>,
    Chris Angelico <> 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".
     
    Roy Smith, Jan 23, 2013
    #4
  5. 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


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

    iQEcBAEBAgAGBQJRAG+jAAoJEAOzoR8eZTzgfqcH/jkzORjA64IPtyrPTPn61Owh
    Ng7xsU4pNxUKiJR0qFZXfmG5XTIgmKqBq9+so4ZcuL0c1xqlKNCTbFj+xngd20pZ
    av3UT65cqxnmaw8E5FNQliUFCm+d07ewMoFRyEM0c8J7xMTN8q3mo5WEC9XfQIJ9
    km59y2CV363Cs7DA5nAKTTn/sEUCmYogybnLooz6PUQInse1MBmRveuvEr6z7g/Y
    o5Wb3PxNWKM1UILEltaFOFe3TXqnUfOfWyNDqUrbATDIeMWsaA8ykcUQb0YzPMN7
    IeQG5xz/myalNuMgQpUh5r1LAAcwUHP5ThG2K1PCjXodrnRN4Km8jABPZKAMuzI=
    =9uJn
    -----END PGP SIGNATURE-----
     
    Evan Driscoll, Jan 23, 2013
    #5
  6. On Thu, Jan 24, 2013 at 9:47 AM, 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:
    > 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
     
    Chris Angelico, Jan 23, 2013
    #6
  7. Coolgg

    Tim Chase Guest

    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
     
    Tim Chase, Jan 23, 2013
    #7
  8. Coolgg

    Terry Reedy Guest

    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
     
    Terry Reedy, Jan 24, 2013
    #8
  9. Coolgg

    Coolgg Guest

    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, Jan 24, 2013
    #9
  10. Coolgg

    Coolgg Guest

    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, Jan 24, 2013
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Page
    Replies:
    1
    Views:
    490
    Michael Borgwardt
    Sep 9, 2004
  2. Replies:
    2
    Views:
    1,964
    Ian Shef
    Apr 20, 2005
  3. Replies:
    5
    Views:
    700
  4. Andy B

    textbox values arent showing up?

    Andy B, Jan 25, 2008, in forum: ASP .Net
    Replies:
    1
    Views:
    384
    Jignesh
    Jan 25, 2008
  5. Mr. Bill
    Replies:
    2
    Views:
    106
    Mr. Bill
    Jan 17, 2011
Loading...

Share This Page