FAQ
I'm coaching a group of biologists on basic Python scripting. One
of my charges mentioned that he had come across the advice never
to use loops beginning with "while True". Of course, that's one
way to start an infinite loop, but this seems hardly a sufficient
reason to avoid the construct altogether, as long as one includes
an exit that is always reached. (Actually, come to think of it,
there are many situations in which a bona fide infinite loops
(typically within a try: block) is the required construct, e.g.
when implementing an event loop.)

I use "while True"-loops often, and intend to continue doing this
"while True", but I'm curious to know: how widespread is the
injunction against such loops? Has it reached the status of "best
practice"?

TIA!

kynn

Search Discussions

  • Stephen Hansen at Oct 10, 2009 at 8:30 pm

    I use "while True"-loops often, and intend to continue doing this
    "while True", but I'm curious to know: how widespread is the
    injunction against such loops?

    The injunction is nonexistent (save perhaps in people coming from another
    language who insist that Python just /must/ have a "proper" do-while
    construct). "while True" with an exit-test at the end is idiomatic, how you
    spell "do-while" in Python. There's nothing at all wrong with it, and no
    real Python programmer will ever say don't-do-it.

    Okay, some people prefer to spell it 'while 1', but its the same difference.

    Yeah, you have to be certain the exit condition is there and properly formed
    so it can exit (unless you're using a generator which never empties, of
    course). But you have to make sure you have a proper exit condition on any
    looping construct anyways.

    No idea where your charge came across the advice, but its nonsense.


    Has it reached the status of "best
    practice"?
    Its simply the correct way to spell a do-while or intentionally infinite
    loop in Python, always has been.

    HTH,

    --S
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20091010/a036f38c/attachment.htm>
  • Boris Arloff at Oct 10, 2009 at 8:58 pm
    I agree there is no rap against "while True"-loops.? As an example these are very useful especially when receiving continuous data over a queue, pipe socket, or over any other connection.? You set to block, receive data, then?process data and?finally loop around to wait for next data segment.? Of course should protect against problems with try-except? wrappers and by handling exit conditions (e.g. "break") when appropriate.
    ?
    Is the problem with the specific syntax "while True:" or is it with having infinite loop constructs at all?

    --- On Sat, 10/10/09, Stephen Hansen wrote:


    From: Stephen Hansen <apt.shansen at gmail.com>
    Subject: Re: The rap against "while True:" loops
    To: python-list at python.org
    Date: Saturday, October 10, 2009, 8:30 PM




    I use "while True"-loops often, and intend to continue doing this
    "while True", but I'm curious to know: how widespread is the
    injunction against such loops?


    The injunction is nonexistent (save perhaps in people coming from another language who insist that Python just /must/ have a "proper" do-while construct). "while True" with an exit-test at the end is idiomatic, how you spell "do-while" in Python. There's nothing at all wrong with it, and no real Python programmer will ever say don't-do-it.


    Okay, some people prefer to spell it 'while 1', but its the same difference.


    Yeah, you have to be certain the exit condition is there and properly formed so it can exit (unless you're using a generator which never empties, of course). But you have to make sure you have a proper exit condition on any looping construct anyways.
    ?
    No idea where your charge came across the advice, but its nonsense.




    ?Has it reached the status of "best
    practice"?



    Its simply the correct way to spell a do-while or intentionally infinite loop in Python, always has been.


    HTH,


    --S
    -----Inline Attachment Follows-----
  • Mensanator at Oct 10, 2009 at 9:20 pm

    On Oct 10, 3:15?pm, kj wrote:
    I'm coaching a group of biologists on basic Python scripting. ?One
    of my charges mentioned that he had come across the advice never
    to use loops beginning with "while True". ?Of course, that's one
    way to start an infinite loop, but this seems hardly a sufficient
    reason to avoid the construct altogether, as long as one includes
    an exit that is always reached. ?(Actually, come to think of it,
    there are many situations in which a bona fide infinite loops
    (typically within a try: block) is the required construct, e.g.
    when implementing an event loop.)

    I use "while True"-loops often, and intend to continue doing this
    "while True", but I'm curious to know: how widespread is the
    injunction against such loops? ?Has it reached the status of "best
    practice"?
    If you know this "exit that is always reached",
    why do you pretend not to know it by writing
    "while True"?
    TIA!

    kynn
  • Kj at Oct 10, 2009 at 10:02 pm
    In <01ccc46d-5ea9-4dfe-ba22-699c6b859f00 at v36g2000yqv.googlegroups.com> Mensanator <mensanator at aol.com> writes:
    On Oct 10, 3:15�pm, kj wrote:
    I'm coaching a group of biologists on basic Python scripting. �On>e
    of my charges mentioned that he had come across the advice never
    to use loops beginning with "while True". �Of course, that's one
    way to start an infinite loop, but this seems hardly a sufficient
    reason to avoid the construct altogether, as long as one includes
    an exit that is always reached. �(Actually, come to think of it,
    there are many situations in which a bona fide infinite loops
    (typically within a try: block) is the required construct, e.g.
    when implementing an event loop.)

    I use "while True"-loops often, and intend to continue doing this
    "while True", but I'm curious to know: how widespread is the
    injunction against such loops? �Has it reached the status of "bes>t
    practice"?
    If you know this "exit that is always reached",
    why do you pretend not to know it by writing
    "while True"?
    There's no "pretense" of anything. I just happen to prefer the
    directness of this:

    while True:
    ...
    if test_that_always_succeeds_eventually():
    break
    ...

    over the unnecessary fussiness of this:

    my_prissy_little_indicator_variable = True
    while my_prissy_little_indicator_variable:
    ...
    if test_that_always_succeeds_eventually():
    my_prissy_little_indicator_variable = False
    continue # oh boy this is going to be fun!
    ...

    In fact, if it were up to me, I would have made the fundamental
    looping construct something like

    repeat:
    ...
    if whatever():
    break
    ...

    and made all the other looping constructs as syntatic sugar for
    this one.

    kj
  • Mensanator at Oct 10, 2009 at 10:34 pm

    On Oct 10, 5:02?pm, kj wrote:
    In <01ccc46d-5ea9-4dfe-ba22-699c6b859... at v36g2000yqv.googlegroups.com> Mensanator <mensana... at aol.com> writes:




    On Oct 10, 3:15�pm, kj wrote:
    I'm coaching a group of biologists on basic Python scripting. �On> >e
    of my charges mentioned that he had come across the advice never
    to use loops beginning with "while True". �Of course, that's one
    way to start an infinite loop, but this seems hardly a sufficient
    reason to avoid the construct altogether, as long as one includes
    an exit that is always reached. �(Actually, come to think of it,
    there are many situations in which a bona fide infinite loops
    (typically within a try: block) is the required construct, e.g.
    when implementing an event loop.)
    I use "while True"-loops often, and intend to continue doing this
    "while True", but I'm curious to know: how widespread is the
    injunction against such loops? �Has it reached the status of "bes> >t
    practice"?
    If you know this "exit that is always reached",
    why do you pretend not to know it by writing
    "while True"?
    There's no "pretense" of anything. ?I just happen to prefer the
    directness of this:

    while True:
    ? ? ...
    ? ? if test_that_always_succeeds_eventually():
    ? ? ? ? ?break
    ? ? ...

    over the unnecessary fussiness of this:

    my_prissy_little_indicator_variable = True
    while my_prissy_little_indicator_variable:
    ? ? ...
    ? ? if test_that_always_succeeds_eventually():
    ? ? ? ? my_prissy_little_indicator_variable = False
    ? ? ? ? continue ?# oh boy this is going to be fun!
    ? ? ...

    In fact, if it were up to me, I would have made the fundamental
    looping construct something like

    repeat:
    ? ? ? ...
    ? ? ? if whatever():
    ? ? ? ? ? ?break
    ? ? ? ...
    So, the second set of '...' doesn't get executed.

    When I use

    while not done:
    ...
    if n==1: done = True
    ...

    the loop will actually complete (which is what
    I want) instead of aborting, like yours does.
    I just don't want the loop to execute again.

    If there are things that should not be done,
    I explicity have the code check that:

    ...
    if not done: write_to_file(test)
    ...

    But even if some things are skipped, others
    need not be:

    ....
    n += 1
    ...

    Now, if I did a break before writing to the file,
    I would have to do all kinds of clean-up code
    outside the loop, code that would be run only
    if the exit were abnormal.
    and made all the other looping constructs as syntatic sugar for
    this one.
    Luckily, it's not up to you.
    kj
  • Greg at Oct 12, 2009 at 8:36 am

    Mensanator wrote:

    while not done:
    ...
    if n==1: done = True
    ...
    Seems to me that 'while not done:' is no better than
    'while True:', because in both cases you have to look
    inside the loop to find out what the exit condition
    is.

    Using a more meaningful name for the flag can help,
    but you can't teach someone that just by giving them
    an overly simplified rules such as "never use
    while True:". They'll probably just replace it with
    'while not done:' and think they've improved things,
    without ever really understanding the issue.

    --
    Greg
  • Mensanator at Oct 12, 2009 at 5:35 pm

    On Oct 12, 3:36?am, greg wrote:
    Mensanator wrote:
    while not done:
    ? ? ...
    ? ? if n==1: done = True
    ? ? ...
    Seems to me that 'while not done:' is no better than
    'while True:', because in both cases you have to look
    inside the loop to find out what the exit condition
    is.

    Using a more meaningful name for the flag can help,
    but you can't teach someone that just by giving them
    an overly simplified rules such as "never use
    while True:". They'll probably just replace it with
    'while not done:' and think they've improved things,
    without ever really understanding the issue.
    You're missing the point. It's not that you have to
    look inside for the terminating condition. It's that
    you don't need a break.
    --
    Greg
  • John Reid at Oct 12, 2009 at 6:02 pm

    Mensanator wrote:
    On Oct 12, 3:36?am, greg wrote:
    Mensanator wrote:
    while not done:
    ? ? ...
    ? ? if n==1: done = True
    ? ? ...
    Seems to me that 'while not done:' is no better than
    'while True:', because in both cases you have to look
    inside the loop to find out what the exit condition
    is.

    Using a more meaningful name for the flag can help,
    but you can't teach someone that just by giving them
    an overly simplified rules such as "never use
    while True:". They'll probably just replace it with
    'while not done:' and think they've improved things,
    without ever really understanding the issue.
    You're missing the point. It's not that you have to
    look inside for the terminating condition. It's that
    you don't need a break.
    Nothing wrong with a having a break IMHO.

    while not done:

    seems very dangerous to me as you'd have to

    del done

    before writing the same construct again. That's the sort of thing that
    leads to errors.
  • Ethan Furman at Oct 12, 2009 at 6:22 pm

    Mensanator wrote:
    On Oct 12, 3:36?am, greg wrote:

    Mensanator wrote:
    while not done:
    ? ? ...
    ? ? if n==1: done = True
    ? ? ...
    Seems to me that 'while not done:' is no better than
    'while True:', because in both cases you have to look
    inside the loop to find out what the exit condition
    is.

    Using a more meaningful name for the flag can help,
    but you can't teach someone that just by giving them
    an overly simplified rules such as "never use
    while True:". They'll probably just replace it with
    'while not done:' and think they've improved things,
    without ever really understanding the issue.

    You're missing the point. It's not that you have to
    look inside for the terminating condition. It's that
    you don't need a break.
    What's wrong with breaks?

    I'll agree that they can be overused and abused, but I am not aware of
    *any* programming costruct that cannot be. If you rule out one way of
    doing things for every situation you can end up making messes just as
    bad as the ones you're trying to avoid.

    Good programming, as all good endeavors, requires thinking too.

    ~Ethan~
  • Mensanator at Oct 12, 2009 at 6:32 pm

    On Oct 12, 1:02?pm, John Reid wrote:
    Mensanator wrote:
    On Oct 12, 3:36 am, greg wrote:
    Mensanator wrote:
    while not done:
    ...
    if n==1: done = True
    ...
    Seems to me that 'while not done:' is no better than
    'while True:', because in both cases you have to look
    inside the loop to find out what the exit condition
    is.
    Using a more meaningful name for the flag can help,
    but you can't teach someone that just by giving them
    an overly simplified rules such as "never use
    while True:". They'll probably just replace it with
    'while not done:' and think they've improved things,
    without ever really understanding the issue.
    You're missing the point. It's not that you have to
    look inside for the terminating condition. It's that
    you don't need a break.
    Nothing wrong with a having a break IMHO.
    My opinion is that there is everything wrong with
    having a break. I don't think I have ever used one,
    I write code that doesn't depend on that crutch.
    while not done:

    seems very dangerous to me as you'd have to

    del done

    before writing the same construct again. That's the sort of thing that
    leads to errors.
    Duh. I won't write silly code like that either.
    If I need more than one loop structure then I'll
    do something like

    while not done_with_this


    while not done_with_that

    Besides, since I _always_ initialize the flag
    before entering a loop, the flag can be reused
    and doesn't have to be deleted (as long as the
    loops aren't nested). And since I don't use goto,
    there's no chance the initialization can be avoided.

    The best way to avoid the pitfalls of spaghetti
    code is to not write it in the first place.
  • Falcolas at Oct 12, 2009 at 7:18 pm

    On Oct 12, 12:32?pm, Mensanator wrote:
    On Oct 12, 1:02 pm, John Reid wrote:
    Mensanator wrote:
    On Oct 12, 3:36 am, greg wrote:
    Mensanator wrote:
    while not done:
    ...
    if n==1: done = True
    ...
    Seems to me that 'while not done:' is no better than
    'while True:', because in both cases you have to look
    inside the loop to find out what the exit condition
    is.
    Using a more meaningful name for the flag can help,
    but you can't teach someone that just by giving them
    an overly simplified rules such as "never use
    while True:". They'll probably just replace it with
    'while not done:' and think they've improved things,
    without ever really understanding the issue.
    You're missing the point. It's not that you have to
    look inside for the terminating condition. It's that
    you don't need a break.
    Nothing wrong with a having a break IMHO.
    My opinion is that there is everything wrong with
    having a break. I don't think I have ever used one,
    I write code that doesn't depend on that crutch.


    while not done:
    seems very dangerous to me as you'd have to
    del done
    before writing the same construct again. That's the sort of thing that
    leads to errors.
    Duh. I won't write silly code like that either.
    If I need more than one loop structure then I'll
    do something like

    ? ? while not done_with_this

    ? ? while not done_with_that

    Besides, since I _always_ initialize the flag
    before entering a loop, the flag can be reused
    and doesn't have to be deleted (as long as the
    loops aren't nested). And since I don't use goto,
    there's no chance the initialization can be avoided.

    The best way to avoid the pitfalls of spaghetti
    code is to not write it in the first place.
    How do you manage code where you need to drop out of a neatly written
    for or while loop early? I don't use break frequently, but just like
    gotos, it does have it's place in well written code.

    Glad to hear, by the way, that you don't use gotos in Python. =D

    Garrick
  • Mensanator at Oct 12, 2009 at 9:11 pm

    On Oct 12, 2:18?pm, Falcolas wrote:
    On Oct 12, 12:32?pm, Mensanator wrote:




    On Oct 12, 1:02 pm, John Reid wrote:
    Mensanator wrote:
    On Oct 12, 3:36 am, greg wrote:
    Mensanator wrote:
    while not done:
    ...
    if n==1: done = True
    ...
    Seems to me that 'while not done:' is no better than
    'while True:', because in both cases you have to look
    inside the loop to find out what the exit condition
    is.
    Using a more meaningful name for the flag can help,
    but you can't teach someone that just by giving them
    an overly simplified rules such as "never use
    while True:". They'll probably just replace it with
    'while not done:' and think they've improved things,
    without ever really understanding the issue.
    You're missing the point. It's not that you have to
    look inside for the terminating condition. It's that
    you don't need a break.
    Nothing wrong with a having a break IMHO.
    My opinion is that there is everything wrong with
    having a break. I don't think I have ever used one,
    I write code that doesn't depend on that crutch.
    while not done:
    seems very dangerous to me as you'd have to
    del done
    before writing the same construct again. That's the sort of thing that
    leads to errors.
    Duh. I won't write silly code like that either.
    If I need more than one loop structure then I'll
    do something like
    ? ? while not done_with_this
    ? ? while not done_with_that
    Besides, since I _always_ initialize the flag
    before entering a loop, the flag can be reused
    and doesn't have to be deleted (as long as the
    loops aren't nested). And since I don't use goto,
    there's no chance the initialization can be avoided.
    The best way to avoid the pitfalls of spaghetti
    code is to not write it in the first place.
    How do you manage code where you need to drop out of a neatly written
    for or while loop early?
    I don't. If I thought there would ever be a case when
    a for loop had to exit early, I wouldn't use a for loop.

    Similarly, if I ever felt the need to escape from a
    while loop, I would rewrite it to avoid that situation.
    I don't use break frequently, but just like
    gotos, it does have it's place in well written code.

    Glad to hear, by the way, that you don't use gotos in Python. =D
    Python doesn't have goto? Gee, I guess I never looked for
    one. Learned my lesson from Pascal, eh?
    Garrick
  • Brian Blais at Oct 12, 2009 at 10:09 pm

    On Oct 12, 2009, at 15:18 , Falcolas wrote:
    Glad to hear, by the way, that you don't use gotos in Python. =D
    actually, it is there. http://entrian.com/goto/

    I particularly like the comefrom construct!


    bb
    --
    Brian Blais
    bblais at bryant.edu
    http://web.bryant.edu/~bblais



    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20091012/ab8a5cdb/attachment.htm>
  • Steven D'Aprano at Oct 13, 2009 at 4:48 am

    On Mon, 12 Oct 2009 11:32:27 -0700, Mensanator wrote:

    Nothing wrong with a having a break IMHO.
    My opinion is that there is everything wrong with having a break. I
    don't think I have ever used one, I write code that doesn't depend on
    that crutch.

    Using break can avoid a lot of complication in loops. There's no need to
    force every loop to have a single exit point (or for that matter, for
    every function to have a single return). Compare the straightforward
    implementation of a simple linear search:

    for item in seq:
    if cond(item):
    print item
    break

    versus doing it without a break:

    found = False
    for item in seq:
    if not found and cond(item):
    print item

    or:

    found = False
    seq = iter(seq)
    while not found:
    item = seq.next()
    found = cond(item)
    if found:
    print item

    The first is obviously correct, and efficient (it stops searching when it
    has found a result). The second and third avoid using a break, but at the
    cost of complicated, inefficient code which isn't obviously correct. If
    you need to post-process item before returning, it's simple to replace
    the return with a break.

    The best way to avoid the pitfalls of spaghetti code is to not write it
    in the first place.

    break does not necessarily lead to spaghetti code. Avoiding break just
    because it is a "goto" is cargo-cult programming -- following the magic
    incantations with no understanding of the *reasons* for when gotos should
    be used and avoided.

    The danger with goto is that it is an *unstructured* jump. break,
    continue, return, yield, for, while are all *structured* jumps. They can
    be abused, like anything, but they're not inherently dangerous.



    --
    Steven
  • Marco Mariani at Oct 14, 2009 at 8:53 am

    Dennis Lee Bieber wrote:

    One thing to note is that "break" ONLY exits the innermost loop --
    Ada adds the confusion that one could define a label on the loops, and
    have the innermost use
    exit outer_label [when condition]


    THAT I find scary... Since you have to match the label name to
    something that occurs somewhere prior to the "exit", and THEN have to
    find the end of that loop.
    But we have exceptions. And I know somebody, in other languages, thinks
    it's a Best Practice to avoid using exceptions for flow control.

    Thankfully, python programmers are less dogmatic, and use whatever makes
    sense to use. I hope.
  • Tim Rowe at Oct 14, 2009 at 3:43 pm

    2009/10/14 Marco Mariani <marco at sferacarta.com>:
    Dennis Lee Bieber wrote:
    ? ? ? ?One thing to note is that "break" ONLY exits the innermost loop --
    Ada adds the confusion that one could define a label on the loops, and
    have the innermost use
    ? ? ? ?exit outer_label [when condition]


    ? ? ? ?THAT I find scary... Since you have to match the label name to
    something that occurs somewhere prior to the "exit", and THEN have to
    find the end of that loop.
    But we have exceptions.
    So has Ada.
    And I know somebody, in other languages, thinks it's
    a Best Practice to avoid using exceptions for flow control.

    Thankfully, python programmers are less dogmatic, and use whatever makes
    sense to use. I hope.
    Absolutely. And it doesn't make sense to use exceptions for flow control :-)

    --
    Tim Rowe
  • TerryP at Oct 14, 2009 at 4:14 pm
    When all is said and done, is not all looping *basically* equivalent
    to something like this?

    begin_loop:
    unless TEST
    goto end_loop
    ;; loop body here
    if TEST
    goto begin_loop
    end_loop:

    Which could likely be used to implement something like:

    while TEST:
    # loop body here

    in any highly expressive language; which in of it self displays
    something about Computer Science.


    or am I just talking out my ass?



    I've watched this thread with some interest, but really it sounds to
    me like the metrics are getting rather lax and this will probably end
    up on par with a for (i=0; i < count; i++) versus for (i=0; i < count;
    i--) discussion. By that, I mean:


    Fruitful conversation but there is no one spoon for every bowl.

    --
    TerryP.
    Just Another Programmer.
  • Jorgen Grahn at Oct 14, 2009 at 8:17 pm

    On Wed, 2009-10-14, Marco Mariani wrote:
    Dennis Lee Bieber wrote:
    One thing to note is that "break" ONLY exits the innermost loop --
    Ada adds the confusion that one could define a label on the loops, and
    have the innermost use
    exit outer_label [when condition]


    THAT I find scary... Since you have to match the label name to
    something that occurs somewhere prior to the "exit", and THEN have to
    find the end of that loop.
    But we have exceptions. And I know somebody, in other languages, thinks
    it's a Best Practice to avoid using exceptions for flow control.
    A lot of C++ programmers think so, and Stroustrup himself says
    "exceptions are for exceptional things" or something to that effect.
    Is that what you're thinking of?

    Thankfully, Stroustrup doesn't use the dreaded phrase "Best Practice",
    which as far as I can tell is designed to shut down rational thought
    in the audience.
    Thankfully, python programmers are less dogmatic, and use whatever makes
    sense to use. I hope.
    Calling it "dogmatic" is unfair. C++ is very different from Python,
    and has a different implementation of exceptions. You also tend to use
    the language to solve a different set of problems.

    That said, I still don't fully understand the rationale behind that
    advice or rule ... so I'm willing to break it, and sometimes I do.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
  • Steven D'Aprano at Oct 14, 2009 at 11:11 pm

    On Wed, 14 Oct 2009 20:17:40 +0000, Jorgen Grahn wrote:

    But we have exceptions. And I know somebody, in other languages, thinks
    it's a Best Practice to avoid using exceptions for flow control.
    A lot of C++ programmers think so, and Stroustrup himself says
    "exceptions are for exceptional things" or something to that effect. Is
    that what you're thinking of?

    Thankfully, Stroustrup doesn't use the dreaded phrase "Best Practice",
    which as far as I can tell is designed to shut down rational thought in
    the audience.
    Thankfully, python programmers are less dogmatic, and use whatever
    makes sense to use. I hope.
    Calling it "dogmatic" is unfair. C++ is very different from Python, and
    has a different implementation of exceptions. You also tend to use the
    language to solve a different set of problems.

    That said, I still don't fully understand the rationale behind that
    advice or rule ... so I'm willing to break it, and sometimes I do.
    Setting up a try...except block is cheap in Python. According to my
    tests, the overhead is little more than that of a single pass statement.

    But actually raising and catching the exception is not cheap. If you use
    a lot of exceptions for flow control, performance will probably suffer.

    In C++, exceptions are expensive, whether you catch one or not.

    Also, using exceptions this way is a structured form of GOTO -- it's easy
    to abuse and turn it into spaghetti code. Actually, not that easy to
    abuse, because you can't jump back into the try block. It's more like a
    multi-level break outside of a loop than a general GOTO.




    --
    Steven
  • Tim Rowe at Oct 16, 2009 at 5:30 pm

    2009/10/15 Steven D'Aprano <steve at remove-this-cybersource.com.au>:

    Setting up a try...except block is cheap in Python. According to my
    tests, the overhead is little more than that of a single pass statement.

    But actually raising and catching the exception is not cheap. If you use
    a lot of exceptions for flow control, performance will probably suffer.

    In C++, exceptions are expensive, whether you catch one or not.

    Also, using exceptions this way is a structured form of GOTO -- it's easy
    to abuse and turn it into spaghetti code. Actually, not that easy to
    abuse, because you can't jump back into the try block. It's more like a
    multi-level break outside of a loop than a general GOTO.
    I don't think it's *only* the performance thing, it's also clarity.
    The understood meaning of throwing an exception is to say "something
    happened that shouldn't have". If one uses it when something has
    happened that *should* have, because it happens to have the right
    behaviour (even if the overhead doesn't matter), then one is
    misrepresenting the program logic.

    --
    Tim Rowe
  • Jorgen Grahn at Oct 21, 2009 at 9:52 pm
    On Wed, 2009-10-14, Steven D'Aprano wrote:
    ...
    Setting up a try...except block is cheap in Python. According to my
    tests, the overhead is little more than that of a single pass statement.

    But actually raising and catching the exception is not cheap. If you use
    a lot of exceptions for flow control, performance will probably suffer.
    You seem to have experimented with this, so you might be right.
    In C++, exceptions are expensive, whether you catch one or not.
    I am not sure that is objectively true, even if you consider that
    "expensive" among C++ users often means "costs more than a semi-decent
    alternative". For example, Stroustrup claimed back in 1994 that the
    non-catching case can be implemented at no speed cost or no memory
    usage cost (Design and Evolution of C++, 1994, p397).

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
  • Aahz at Oct 16, 2009 at 7:07 pm
    In article <mailman.1540.1255714251.2807.python-list at python.org>,
    Tim Rowe wrote:
    The understood meaning of throwing an exception is to say "something
    happened that shouldn't have". If one uses it when something has
    happened that *should* have, because it happens to have the right
    behaviour (even if the overhead doesn't matter), then one is
    misrepresenting the program logic.
    Except, of course, that your "understood meaning" is wrong for Python.
    Perhaps you should go look up StopIteration.
    --
    Aahz (aahz at pythoncraft.com) <*> http://www.pythoncraft.com/

    "To me vi is Zen. To use vi is to practice zen. Every command is a
    koan. Profound to the user, unintelligible to the uninitiated. You
    discover truth everytime you use it." --reddy at lion.austin.ibm.com
  • Steven D'Aprano at Oct 17, 2009 at 7:55 am

    On Fri, 16 Oct 2009 18:30:50 +0100, Tim Rowe wrote:

    Also, using exceptions this way is a structured form of GOTO -- it's
    easy to abuse and turn it into spaghetti code. Actually, not that easy
    to abuse, because you can't jump back into the try block. It's more
    like a multi-level break outside of a loop than a general GOTO.
    I don't think it's *only* the performance thing, it's also clarity. The
    understood meaning of throwing an exception is to say "something
    happened that shouldn't have". If one uses it when something has
    happened that *should* have, because it happens to have the right
    behaviour (even if the overhead doesn't matter), then one is
    misrepresenting the program logic.
    No, you have a fundamental misunderstanding. They're called exceptions,
    not errors, because they represent exceptional cases. Often errors are
    exceptional cases, but they're not the only sort of exceptional case.

    Python uses exceptions for flow control: e.g. for-loops swallow
    StopIteration or IndexError to indicate the end of the loop. In the
    context of a for-loop, StopIteration or IndexError doesn't represent an
    error. It doesn't represent an unexpected case. It represents an
    expected, but exceptional (special) case: we expect that most sequences
    are finite, and it is normal to eventually reach the end of the sequence,
    after which the loop must change behaviour.

    Similarly, it's hardly an *error* for [1, 2, 3].index(5) to fail -- who
    is to say that the list is supposed to have 5 in it? ValueError (a
    slightly misleading name in this situation) is used to indicate an
    exceptional, but not unexpected, occurrence.

    Likewise, KeyboardInterrupt is used to allow the user to halt processing;
    SystemExit is used to shut down the Python virtual machine; and warnings
    are implemented using exceptions. There may be others among the built-ins
    and standard library, but even if there aren't, there is plenty of
    precedence for us to do the same.


    --
    Steven
  • Tim Rowe at Oct 17, 2009 at 12:12 pm

    2009/10/17 Steven D'Aprano <steve at remove-this-cybersource.com.au>:

    No, you have a fundamental misunderstanding. They're called exceptions,
    not errors, because they represent exceptional cases. Often errors are
    exceptional cases, but they're not the only sort of exceptional case.
    The whole reason for the mechanism, across all languages that have it,
    is to deal with situations that you don't know how to deal with
    locally. That's why they have the overhead that they do.
    Python uses exceptions for flow control:
    Yes, and in some cases I think that's a serious language wart. Not
    enough to put me off the language, but a serious wart nevertheless.
    Similarly, it's hardly an *error* for [1, 2, 3].index(5) to fail -- who
    is to say that the list is supposed to have 5 in it? ValueError (a
    slightly misleading name in this situation) is used to indicate an
    exceptional, but not unexpected, occurrence.
    That one is, I think, a legitimate use of an exception. The result
    returned by index is defined if the index is in bounds. If not, index
    doesn't know whether it was supposed to be in bounds or not, and so
    can't handle the case locally. It could suggest an error or merely
    (IMHO) poor programming. Because index cannot know what the proper
    action is, an exception is the appropriate response.
    Likewise, KeyboardInterrupt is used to allow the user to halt processing;
    SystemExit is used to shut down the Python virtual machine; and warnings
    are implemented using exceptions.
    Again, I think it's fair to treat a program being killed from outside
    as an exception as far as the program is concerned. They're not things
    the program has brought about, and the original handling code has no
    way of knowinng what response is appropriate. Same with warnings; they
    *probably* shouldn't happen but only the application programmer can
    know whether they should or not.

    The point is that an exception causes a change in program flow, so of
    course they're used for flow control. It's what they do. The question
    is in what cases it's appropriate to use them.

    --
    Tim Rowe
  • Terry Reedy at Oct 17, 2009 at 10:18 pm

    Steven D'Aprano wrote:
    On Fri, 16 Oct 2009 18:30:50 +0100, Tim Rowe wrote:

    Also, using exceptions this way is a structured form of GOTO -- it's
    easy to abuse and turn it into spaghetti code. Actually, not that easy
    to abuse, because you can't jump back into the try block. It's more
    like a multi-level break outside of a loop than a general GOTO.
    I don't think it's *only* the performance thing, it's also clarity. The
    understood meaning of throwing an exception is to say "something
    happened that shouldn't have". If one uses it when something has
    happened that *should* have, because it happens to have the right
    behaviour (even if the overhead doesn't matter), then one is
    misrepresenting the program logic.
    No, you have a fundamental misunderstanding. They're called exceptions,
    not errors, because they represent exceptional cases. Often errors are
    exceptional cases, but they're not the only sort of exceptional case.

    Python uses exceptions for flow control: e.g. for-loops swallow
    StopIteration or IndexError to indicate the end of the loop. In the
    context of a for-loop, StopIteration or IndexError doesn't represent an
    error. It doesn't represent an unexpected case. It represents an
    expected, but exceptional (special) case: we expect that most sequences
    are finite, and it is normal to eventually reach the end of the sequence,
    after which the loop must change behaviour.

    Similarly, it's hardly an *error* for [1, 2, 3].index(5) to fail -- who
    is to say that the list is supposed to have 5 in it? ValueError (a
    slightly misleading name in this situation) is used to indicate an
    exceptional, but not unexpected, occurrence.

    Likewise, KeyboardInterrupt is used to allow the user to halt processing;
    SystemExit is used to shut down the Python virtual machine; and warnings
    are implemented using exceptions. There may be others among the built-ins
    and standard library, but even if there aren't, there is plenty of
    precedence for us to do the same.
    Nicely put. Programmers are exceptional people, but not erroneous, in
    spite of nerd stereotypes ;-).

    tjr




    From http Sun Oct 18 00:22:59 2009
    From: http (Paul Rubin)
    Date: 17 Oct 2009 15:22:59 -0700
    Subject: The rap against "while True:" loops
    References: <01ccc46d-5ea9-4dfe-ba22-699c6b859f00@v36g2000yqv.googlegroups.com>
    <mailman.1540.1255714251.2807.python-list@python.org>
    <0062fc72$0$26941$c3 <mailman.1589.1255781573.2807.python-list@python.org>
    <hbckev$96g$1@panix3.panix.com>
    <7xmy3peq3s.fsf@ruckus.brouhaha.com>
    <mailman.1612.1255817879.2807.python-list@python.org>
    Message-ID: <7xws2tace4.fsf@ruckus.brouhaha.com>

    Terry Reedy <tjreedy at udel.edu> writes:
    d[key] += value
    Yes, the motivation was to reduce 4 lines to 1 line for a common use
    case, and not because of any sense of 'inappropriateness'.
    Reducing 4 confusing lines to 1 clear one is almost always appropriate.
  • Aahz at Oct 17, 2009 at 2:30 pm
    In article <mailman.1589.1255781573.2807.python-list at python.org>,
    Tim Rowe wrote:
    The point is that an exception causes a change in program flow, so of
    course they're used for flow control. It's what they do. The question
    is in what cases it's appropriate to use them.
    Standard Python idiom:

    try:
    d[key] += value
    except KeyError:
    d[key] = value

    Maybe you need to re-think "appropriate".
    --
    Aahz (aahz at pythoncraft.com) <*> http://www.pythoncraft.com/

    "To me vi is Zen. To use vi is to practice zen. Every command is a
    koan. Profound to the user, unintelligible to the uninitiated. You
    discover truth everytime you use it." --reddy at lion.austin.ibm.com
  • Aahz at Oct 17, 2009 at 8:27 pm
    In article <7xmy3peq3s.fsf at ruckus.brouhaha.com>,
    Paul Rubin wrote:
    aahz at pythoncraft.com (Aahz) writes:
    Standard Python idiom:

    try:
    d[key] += value
    except KeyError:
    d[key] = value

    Maybe you need to re-think "appropriate".
    But more recent style prefers:

    d = collections.defaultdict(int)
    ...
    d[key] += value
    That was a trivial example; non-trivial examples not addressed by
    defaultdict are left as an exercise for the reader.
    --
    Aahz (aahz at pythoncraft.com) <*> http://www.pythoncraft.com/

    "To me vi is Zen. To use vi is to practice zen. Every command is a
    koan. Profound to the user, unintelligible to the uninitiated. You
    discover truth everytime you use it." --reddy at lion.austin.ibm.com
  • Terry Reedy at Oct 17, 2009 at 10:17 pm

    Paul Rubin wrote:
    aahz at pythoncraft.com (Aahz) writes:
    Standard Python idiom:

    try:
    d[key] += value
    except KeyError:
    d[key] = value

    Maybe you need to re-think "appropriate".
    But more recent style prefers:

    d = collections.defaultdict(int)
    ...
    d[key] += value
    Yes, the motivation was to reduce 4 lines to 1 line for a common use
    case, and not because of any sense of 'inappropriateness'.

    tjr
  • Steven D'Aprano at Oct 18, 2009 at 5:18 am

    On Sat, 17 Oct 2009 15:22:59 -0700, Paul Rubin wrote:

    Terry Reedy <tjreedy at udel.edu> writes:
    d[key] += value
    Yes, the motivation was to reduce 4 lines to 1 line for a common use
    case, and not because of any sense of 'inappropriateness'.
    Reducing 4 confusing lines to 1 clear one is almost always appropriate.
    This is true, but there is nothing confusing about "Asking for
    forgiveness is better than asking for permission".

    For the record, the four lines Paul implies are "confusing" are:

    try:
    d[key] += value
    except KeyError:
    d[key] = value

    Paul, if that confuses you, perhaps you should consider a change of
    career. *wink*

    On the other hand:

    d = collections.defaultdict(int)
    d[key] += value

    is confusing, at least to me. I would expect the argument to defaultdict
    to be the value used as a default, not a callable. In other words, I
    would expect the above to try adding the type `int` to the integer
    `value` and fail, and wonder why it wasn't written as:

    d = collections.defaultdict(0)
    d[key] += value

    Having thought about it, I can see why defaultdict is done that way,
    instead of this:

    class MyDefaultDict(dict):
    def __init__(self, default=None):
    self._default = default
    def __getitem__(self, key):
    if key in self:
    return self[key]
    else:
    return self._default

    And here's why this doesn't work too well:
    d = MyDefaultDict([])
    d['a'] = [1,2]
    d['b'] = [3,4,5]
    d
    {'a': [1, 2], 'b': [3, 4, 5]}
    d['c'] += [6,7]
    d
    {'a': [1, 2], 'c': [6, 7], 'b': [3, 4, 5]}

    So far so good. But wait:
    d['d'] += [8]
    d
    {'a': [1, 2], 'c': [6, 7, 8], 'b': [3, 4, 5], 'd': [6, 7, 8]}

    Oops. So even though it's initially surprising and even confusing, the
    API for collections.defaultdict functionally more useful.



    --
    Steven
  • Steven D'Aprano at Oct 18, 2009 at 9:07 am

    On Sat, 17 Oct 2009 23:37:51 -0700, Paul Rubin wrote:

    Steven D'Aprano <steve at REMOVE-THIS-cybersource.com.au> writes:
    For the record, the four lines Paul implies are "confusing" are:

    try:
    d[key] += value
    except KeyError:
    d[key] = value
    Consider what happens if the computation of "key" or "value" itself
    raises KeyError.
    How does using a defaultdict for d save you from that problem?

    table = {101: 'x', 202: 'y'}
    data = {'a': 1, 'b': 2}
    d = collections.defaultdict(int)
    d[table[303]] += data['c']


    It may not be appropriate to turn table and data into defaultdicts --
    there may not be a legitimate default you can use, and the key-lookup
    failure may be a fatal error. So defaultdict doesn't solve your problem.

    If you need to distinguish between multiple expressions that could raise
    exceptions, you can't use a single try to wrap them all. If you need to
    make that distinction, then the following is no good:

    try:
    key = keytable[s]
    value = datatable[t]
    d[key] += value
    except KeyError:
    print "An exception occurred somewhere"

    But if you need to treat all three possible KeyErrors identically, then
    the above is a perfectly good solution.


    --
    Steven
  • Lie Ryan at Oct 18, 2009 at 9:21 am

    Paul Rubin wrote:
    Steven D'Aprano <steve at REMOVE-THIS-cybersource.com.au> writes:
    For the record, the four lines Paul implies are "confusing" are:

    try:
    d[key] += value
    except KeyError:
    d[key] = value
    Consider what happens if the computation of "key" or "value" itself
    raises KeyError.
    Isn't key and value just a simple variables/names? Why should it ever
    raises KeyError? The only other error that try-block code could ever
    possibly throw are NameError and possibly MemoryError.


    From http Sun Oct 18 11:31:19 2009
    From: http (Paul Rubin)
    Date: 18 Oct 2009 02:31:19 -0700
    Subject: The rap against "while True:" loops
    References: <01ccc46d-5ea9-4dfe-ba22-699c6b859f00@v36g2000yqv.googlegroups.com>
    <mailman.1589.1255781573.2807.python-list@python.org>
    <hbckev$96g$1@panix3.panix.com>
    <mailman.1636.1255853212.2807.python-list@python.org>
    Message-ID: <7x1vl1nj4o.fsf@ruckus.brouhaha.com>

    Hendrik van Rooyen <hendrik at microcorp.co.za> writes:
    Standard Python idiom:

    if key in d:
    d[key] += value
    else:
    d[key] = value
    The issue is that uses two lookups. If that's ok, the more usual idiom is:

    d[key] = value + d.get(key, 0)
  • Ben Finney at Oct 18, 2009 at 9:43 am

    Lie Ryan <lie.1296 at gmail.com> writes:

    Paul Rubin wrote:
    Steven D'Aprano <steve at REMOVE-THIS-cybersource.com.au> writes:
    For the record, the four lines Paul implies are "confusing" are:

    try:
    d[key] += value
    except KeyError:
    d[key] = value
    Consider what happens if the computation of "key" or "value" itself
    raises KeyError.
    Isn't key and value just a simple variables/names?
    In that example, yes. Paul is encouraging the reader to think of more
    complex cases where they are compound expressions, that can therefore
    raise other errors depending on what those expressions contain.

    --
    \ ?Don't be afraid of missing opportunities. Behind every failure |
    `\ is an opportunity somebody wishes they had missed.? ?Jane |
    _o__) Wagner, via Lily Tomlin |
    Ben Finney
  • Lie Ryan at Oct 18, 2009 at 5:30 pm

    Ben Finney wrote:
    Lie Ryan <lie.1296 at gmail.com> writes:
    Paul Rubin wrote:
    Steven D'Aprano <steve at REMOVE-THIS-cybersource.com.au> writes:
    For the record, the four lines Paul implies are "confusing" are:

    try:
    d[key] += value
    except KeyError:
    d[key] = value
    Consider what happens if the computation of "key" or "value" itself
    raises KeyError.
    Isn't key and value just a simple variables/names?
    In that example, yes. Paul is encouraging the reader to think of more
    complex cases where they are compound expressions, that can therefore
    raise other errors depending on what those expressions contain.
    If key and value had been anything but simple variable/name, then
    definitely you're writing the try-block the wrong way. try-block must be
    kept as simple as possible.

    Here is a simple, and effective way to mitigate the concern about
    compound expressions:
    key = complex_compound_expression_to_calculate_key
    value = complex_compound_expression_to_calculate_value
    try:
    d[key] += value
    except KeyError:
    d[key] = value


    The point is: "complex expressions and exceptions are used for different
    purpose"


    From http Sun Oct 18 19:53:41 2009
    From: http (Paul Rubin)
    Date: 18 Oct 2009 10:53:41 -0700
    Subject: The rap against "while True:" loops
    References: <01ccc46d-5ea9-4dfe-ba22-699c6b859f00@v36g2000yqv.googlegroups.com>
    <mailman.1540.1255714251.2807.python-list@python.org>
    <mailman.1589.1255781573.2807.python-list@python.org>
    <hbckev$96g$1@panix3.panix.com>
    <7xmy3peq3s.fsf@ruckus.brouhaha.com>
    <mailman.1612.1255817879.2807.python-list@python.org>
    <7xws2tace4.fsf@ruckus.brouhaha.com>
    <02ea93d3$0$1384$c3e8da3@news.astraweb.com>
    <7x4opx2on4.fsf@ruckus.brouhaha.com>
    <4adade1a$1@dnews.tpgi.com.au> <87vdidkpfv.fsf@benfinney.id.au>
    <4adb50aa$1@dnews.tpgi.com.au>
    Message-ID: <7x8wf88u6y.fsf@ruckus.brouhaha.com>

    Lie Ryan <lie.1296 at gmail.com> writes:
    If key and value had been anything but simple variable/name, then
    definitely you're writing the try-block the wrong way. try-block must
    be kept as simple as possible.
    Avoiding the try-block completely is the simplest possibility of them all.
  • Hendrik van Rooyen at Oct 18, 2009 at 8:08 am

    On Saturday, 17 October 2009 16:30:55 Aahz wrote:
    In article <mailman.1589.1255781573.2807.python-list at python.org>,

    Tim Rowe wrote:
    The point is that an exception causes a change in program flow, so of
    course they're used for flow control. It's what they do. The question
    is in what cases it's appropriate to use them.
    Standard Python idiom:

    try:
    d[key] += value
    except KeyError:
    d[key] = value

    Maybe you need to re-think "appropriate".
    Standard Python idiom:

    if key in d:
    d[key] += value
    else:
    d[key] = value

    Maybe you need to re-think "appropriate".

    - Hendrik
  • Steven D'Aprano at Oct 18, 2009 at 11:28 am

    On Sat, 17 Oct 2009 13:12:52 +0100, Tim Rowe wrote:

    2009/10/17 Steven D'Aprano <steve at remove-this-cybersource.com.au>:
    No, you have a fundamental misunderstanding. They're called exceptions,
    not errors, because they represent exceptional cases. Often errors are
    exceptional cases, but they're not the only sort of exceptional case.
    The whole reason for the mechanism, across all languages that have it,
    is to deal with situations that you don't know how to deal with locally.
    That confuses me. If I call:

    y = mydict[x]

    how does my knowledge of what to do if x is not a key relate to whether
    the language raises an exception, returns an error code, dumps core, or
    prints "He's not the Messiah, he's a very naughty boy" to stderr?

    You seem to be making a distinction of *intent* which, as far as I can
    tell, doesn't actually exist. What's the difference in intent between
    these?

    y = mydict[x]
    if y == KeyErrorCode:
    handle_error_condition()
    process(y)


    and this?

    try:
    y = mydict[x]
    except KeyError:
    handle_error_condition()
    process(y)


    Neither assumes more or less knowledge of what to do in
    handle_error_condition(). Neither case assumes that the failure of x to
    be a key is an error:

    try:
    y = mydict[x]
    except KeyError:
    process() # working as expected
    else:
    print 'found x in dict, it shouldn't be there'
    sys.exit()

    Either way, whether the language uses error codes or exceptions, the
    decision of what to do in an exceptional situation is left to the user.

    If you'll excuse me pointing out the bleedin' obvious, there are
    differences between error codes and exceptions, but they aren't one of
    intention. Error codes put the onus on the caller to check the code after
    every single call which might fail (or have a buggy program), while
    exceptions use a framework that do most of the heavy lifting.

    That's why they have the overhead that they do.
    Exceptions don't have one common overhead across all languages that use
    them. They have different overhead in different languages -- they're very
    heavyweight in C++ and Java, but lightweight in Python. The Perl
    Exception::Base module claims to be lightweight. The overhead of
    exceptions is related to the implementation of the language.

    Python uses exceptions for flow control:
    Yes, and in some cases I think that's a serious language wart. Not
    enough to put me off the language, but a serious wart nevertheless.
    I disagree with that. I think exceptions are a beautiful and powerful way
    of dealing with flow control, much better than returning a special code,
    and much better than having to check some status function or global
    variable, as so often happens in C. They're more restricted, and
    therefore safer, than goto. They're not a panacea but they're very useful.

    Similarly, it's hardly an *error* for [1, 2, 3].index(5) to fail -- who
    is to say that the list is supposed to have 5 in it? ValueError (a
    slightly misleading name in this situation) is used to indicate an
    exceptional, but not unexpected, occurrence.
    That one is, I think, a legitimate use of an exception. The result
    returned by index is defined if the index is in bounds. If not, index
    doesn't know whether it was supposed to be in bounds or not, and so
    can't handle the case locally. It could suggest an error or merely
    (IMHO) poor programming. Because index cannot know what the proper
    action is, an exception is the appropriate response.
    I think you're confused about what list.index(obj) does. You seem to me
    to be assuming that [1,2,3].index(5) should return the item in position 5
    of the list, and since there isn't one (5 is out of bounds), raise an
    exception. But that's not what it does. It searches the list and returns
    the position at which 5 is found.

    Of course list.index() could have returned an error code instead, like
    str.find() does. But str also has an index() method, which raises an
    exception -- when handling strings, you can Look Before You Leap or Ask
    For Forgiveness Instead Of Permission, whichever you prefer.

    Likewise, KeyboardInterrupt is used to allow the user to halt
    processing; SystemExit is used to shut down the Python virtual machine;
    and warnings are implemented using exceptions.
    Again, I think it's fair to treat a program being killed from outside as
    an exception as far as the program is concerned.
    No, it's not being killed from outside the program -- it's being
    *interrupted* from *inside* the program by the user. What you do in
    response to that interrupt is up to you -- it doesn't necessarily mean
    "kill the program".

    If you kill the program from outside, using (say) kill or the TaskManager
    or something, you don't necessarily get an exception. With kill -9 on
    POSIX systems you won't get anything, because the OS will just yank the
    carpet out from under your program's feet and then drop a safe on it to
    be sure.



    --
    Steven
  • Tim Rowe at Oct 19, 2009 at 10:37 am

    2009/10/18 Steven D'Aprano <steve at remove-this-cybersource.com.au>:

    That confuses me. If I call:

    y = mydict[x]

    how does my knowledge of what to do if x is not a key relate to whether
    the language raises an exception, returns an error code, dumps core, or
    prints "He's not the Messiah, he's a very naughty boy" to stderr?

    You seem to be making a distinction of *intent* which, as far as I can
    tell, doesn't actually exist. What's the difference in intent between
    these?

    y = mydict[x]
    if y == KeyErrorCode:
    ? ?handle_error_condition()
    process(y)


    and this?

    try:
    ? ?y = mydict[x]
    except KeyError:
    ? ?handle_error_condition()
    process(y)
    Nothing -- because both of those are at the level of code where you
    know what to do with the error condition. But if you weren't -- if,
    for example, you were in a library routine and had no idea how the
    routime might be used in the future -- the latter would just become:
    y = mydict[x]
    and the problem is passed on until it gets to somebody who does know.
    In the former case, though, you still need all the error handling code
    even though you don't know how to handle the error, *and* you need to
    exit with an error code of your own, *and* your client needs error
    handling code even though /they/ might not know how to handle the
    error, and so on.
    Neither assumes more or less knowledge of what to do in
    handle_error_condition(). Neither case assumes that the failure of x to
    be a key is an error:
    They both assume that calling handle_error_condition() is an
    appropriate response.
    That's why they have the overhead that they do.
    Exceptions don't have one common overhead across all languages that use
    them. They have different overhead in different languages -- they're very
    heavyweight in C++ and Java, but lightweight in Python.
    As others have pointed out, Python exceptions are cheap to set up, but
    decidedly less cheap to invoke. But I'm not making the efficiency
    argument, I'm making the clarity argument. I don't /quite/ believe
    that Premature Optimisation is the root of all evil, but I wouldn't
    avoid exceptions because of the overhead. In the rare cases where the
    response to an exceptional condition is time (or resource?)-critical
    I'd consider that case to need special handling anyway, and so
    wouldn't treat it as an exception.
    Python uses exceptions for flow control:
    Yes, and in some cases I think that's a serious language wart. Not
    enough to put me off the language, but a serious wart nevertheless.
    I think exceptions are a beautiful and powerful way
    of dealing with flow control, much better than returning a special code,
    and much better than having to check some status function or global
    variable, as so often happens in C. They're more restricted, and
    therefore safer, than goto. They're not a panacea but they're very useful.
    I agree completely -- when they're used in appropriate circumstances.
    Not when they're not.
    I think you're confused about what list.index(obj) does. You seem to me
    to be assuming that [1,2,3].index(5) should return the item in position 5
    of the list, and since there isn't one (5 is out of bounds), raise an
    exception. But that's not what it does. It searches the list and returns
    the position at which 5 is found.
    Yes, sorry, brain fade. But my point remains that the authors of index
    can't know whether the item not being in the list is an error or not,
    can't know how to handle that case, and so passing it to the client as
    an exception is an appropriate response.
    No, it's not being killed from outside the program -- it's being
    *interrupted* from *inside* the program by the user.
    Who -- unless AI has advanced further than I thought -- is *outside*
    the program.

    --
    Tim Rowe
  • Raymond Hettinger at Oct 14, 2009 at 8:23 pm

    And I know somebody, in other languages, thinks
    it's a Best Practice to avoid using exceptions for flow control.
    Ah, now we have two code prions in just one thread.
    I hope no newbie or supervisor reads this thread and latches
    on to those two counter-productive ideas.

    ISTM, both ideas are dangerous contagious because they are
    true in some limited contexts but useless (and harmful)
    when applied to programming in general.

    IIRC, the C++ admonition against using exceptions for flow control
    was rooted in performance concerns specific to that language and
    its compilers. It was not stylistic advice and did not deny that
    flow control exceptions could provide elegant solutions to some
    programming challenges.

    Python's IndexError and KeyError are all about flow control.
    The notion is deeply embedded in the language and it would
    be a disservice to advise people to not use the language as
    designed.

    Likewise, the use of "while True" tends to be more important
    in Python than in other languages because we can't combine
    assignment with a conditional as we can in C. So instead,
    we have this idiom:

    while True:
    s = f.read(blocksize)
    if not s:
    break
    ...

    Suggested further reading for those who are interested:

    "The Little MLer" -- a chunk of this book is devoted to showing
    how exceptions can simplify code that would otherwise be
    somewhat awkward to express (the remainder of the book is devoted
    to thinking about types and how to compose program components).

    "Structured Programming with go to Statements" by Donald Knuth
    has an in-depth comparative analysis of many different looping
    constructs.


    Raymond
  • Bearophile at Oct 16, 2009 at 8:02 pm

    Paul Rubin:

    ?http://scholar.google.com/scholar?cluster368311454828547380

    Keep in mind that the article is 35 years old though, and is purely
    imperative. ?Lots of stuff done with cockamamie looping constructs is
    more cleanly done with Python generators, itertools, higher-order
    functions, etc.
    That's a famous and very good paper, a good read for people that like
    to program.
    The Example1 and Example2 can be rewritten in several different ways,
    but several compilers today are not able to perform such optimizations
    yet, so what Knuth has written there are still among the faster ways
    to implement that algorithm.

    Bye,
    bearophile
  • John Reid at Oct 13, 2009 at 8:44 am

    Mensanator wrote:
    Nothing wrong with a having a break IMHO.
    My opinion is that there is everything wrong with
    having a break. I don't think I have ever used one,
    I write code that doesn't depend on that crutch.
    I guess its crutch-iness is in the eye of the beholder. You seem to have
    a dogmatic view about this.
    while not done:

    seems very dangerous to me as you'd have to

    del done

    before writing the same construct again. That's the sort of thing that
    leads to errors.
    Duh. I won't write silly code like that either.
    If I need more than one loop structure then I'll
    do something like

    while not done_with_this


    while not done_with_that
    This is neither clean or well scoped.
    Besides, since I _always_ initialize the flag
    before entering a loop, the flag can be reused
    and doesn't have to be deleted (as long as the
    loops aren't nested). And since I don't use goto,
    there's no chance the initialization can be avoided.
    Initialising the flag is just another line of code that has to be
    interpreted later. I didn't notice the initialisation in your original post.
    The best way to avoid the pitfalls of spaghetti
    code is to not write it in the first place.
    I agree. With 'break' it is obvious what the code does and there are
    fewer lines to write in the first place and comprehend in the second.
  • Mensanator at Oct 13, 2009 at 3:20 pm

    On Oct 13, 3:44?am, John Reid wrote:
    Mensanator wrote:
    Nothing wrong with a having a break IMHO.
    My opinion is that there is everything wrong with
    having a break. I don't think I have ever used one,
    I write code that doesn't depend on that crutch.
    I guess its crutch-iness is in the eye of the beholder. You seem to have
    a dogmatic view about this.
    No, it's just that the OP was asking whether
    avoiding "while True" is considered Best Practice.
    How can you answer such a question without sounding
    dogmatic?





    while not done:
    seems very dangerous to me as you'd have to
    del done
    before writing the same construct again. That's the sort of thing that
    leads to errors.
    Duh. I won't write silly code like that either.
    If I need more than one loop structure then I'll
    do something like
    ? ? while not done_with_this
    ? ? while not done_with_that
    This is neither clean or well scoped.


    Besides, since I _always_ initialize the flag
    before entering a loop, the flag can be reused
    and doesn't have to be deleted (as long as the
    loops aren't nested). And since I don't use goto,
    there's no chance the initialization can be avoided.
    Initialising the flag is just another line of code that has to be
    interpreted later. I didn't notice the initialisation in your original post.
    "Just another line that has to be interpreted later"
    is a strange comment in the context of "del done".

    The best way to avoid the pitfalls of spaghetti
    code is to not write it in the first place.
    I agree. With 'break' it is obvious what the code does and there are
    fewer lines to write in the first place and comprehend in the second.
    Do you consider Perl golf to be Best Practice?
  • John Reid at Oct 13, 2009 at 4:11 pm

    Mensanator wrote:
    No, it's just that the OP was asking whether
    avoiding "while True" is considered Best Practice.
    How can you answer such a question without sounding
    dogmatic?
    I was just pointing out your style of programming seems inflexible.
    "Just another line that has to be interpreted later"
    is a strange comment in the context of "del done".
    Interpreted in the sense that the maintainer of the code interprets it,
    not the machine.
  • Ethan Furman at Oct 13, 2009 at 4:27 pm

    Mensanator wrote:
    On Oct 13, 3:44?am, John Reid wrote:

    while not done:

    seems very dangerous to me as you'd have to

    del done

    before writing the same construct again. That's the sort of thing that
    leads to errors.
    Duh. I won't write silly code like that either.
    If I need more than one loop structure then I'll
    do something like

    ? ? while not done_with_this

    ? ? while not done_with_that

    Besides, since I _always_ initialize the flag
    before entering a loop, the flag can be reused
    and doesn't have to be deleted (as long as the
    loops aren't nested). And since I don't use goto,
    there's no chance the initialization can be avoided.
    Initialising the flag is just another line of code that has to be
    interpreted later. I didn't notice the initialisation in your original post.

    "Just another line that has to be interpreted later"
    is a strange comment in the context of "del done".
    I don't believe John is advocating using it, just pointing out that an
    extra line is needed -- whether the extra line is "del loop_control_var"
    or "loop_control_var = False", it's still an extra line.

    Mind you, I'm not saying you should change the way you program as it
    seems to work for you, just that there are other ways to write good
    clean programs.

    ~Ethan~
  • Mensanator at Oct 13, 2009 at 9:59 pm

    On Oct 13, 11:27?am, Ethan Furman wrote:
    Mensanator wrote:
    On Oct 13, 3:44 am, John Reid wrote:

    while not done:
    seems very dangerous to me as you'd have to
    del done
    before writing the same construct again. That's the sort of thing that
    leads to errors.
    Duh. I won't write silly code like that either.
    If I need more than one loop structure then I'll
    do something like
    while not done_with_this
    while not done_with_that
    Besides, since I _always_ initialize the flag
    before entering a loop, the flag can be reused
    and doesn't have to be deleted (as long as the
    loops aren't nested). And since I don't use goto,
    there's no chance the initialization can be avoided.
    Initialising the flag is just another line of code that has to be
    interpreted later. I didn't notice the initialisation in your original post.
    "Just another line that has to be interpreted later"
    is a strange comment in the context of "del done".
    I don't believe John is advocating using it, just pointing out that an
    extra line is needed -- whether the extra line is "del loop_control_var"
    or "loop_control_var = False", it's still an extra line.

    Mind you, I'm not saying you should change the way you program as it
    seems to work for you, just that there are other ways to write good
    clean programs.
    And I'm not saying John nor the OP should stop
    using what works for them. But there are certainly
    valid reasons for "don't use while True" to be
    on the "Best Practices" list.

    After all, how many times hve you put 'break'
    in a loop comprehension?
    ~Ethan~
  • Steven D'Aprano at Oct 13, 2009 at 10:24 pm

    On Tue, 13 Oct 2009 14:59:04 -0700, Mensanator wrote:

    And I'm not saying John nor the OP should stop using what works for
    them. But there are certainly valid reasons for "don't use while True"
    to be on the "Best Practices" list.
    "Valid"? Well, maybe. But none of them are convincing to me. The best I
    have seen is that loops should have a single entry point and a single
    exit point, to make it easier to reason about pre- and post-conditions.
    But frankly I'm not convinced that's true -- or at least, multiple exists
    shouldn't *necessarily* leader to difficulty in reasoning about the post-
    condition.


    After all, how many times hve you put 'break' in a loop comprehension?
    What's a loop comprehension?

    Do you mean *list* comprehensions? List comps aren't supposed to be a
    general purpose replacement for for-loops. They are a deliberately cut-
    down version which is easier to read, write and execute than a pure
    Python for-loop:
    from timeit import Timer
    Timer("""L = []
    ... for i in range(20):
    ... L.append(2*i-1)
    ... """, '').repeat()
    [9.7169408798217773, 9.4620440006256104, 9.4636049270629883]
    Timer('[2*i-1 for i in range(20)]', '').repeat()
    [5.6287829875946045, 5.8934588432312012, 5.7950780391693115]

    But the consequence of that simplicity and speed is that they're not as
    general as a for-loop. This was a design decision. But change the design
    and you could have something like this:

    [expr for name in seq until cond]

    which breaks when cond becomes true.


    --
    Steven
  • Greg at Oct 14, 2009 at 12:06 am

    Steven D'Aprano wrote:
    The best I
    have seen is that loops should have a single entry point and a single
    exit point, to make it easier to reason about pre- and post-conditions.
    But frankly I'm not convinced that's true -- or at least, multiple exists
    shouldn't *necessarily* leader to difficulty in reasoning about the post-
    condition.
    It's not all that difficult.

    If you have multiple exit conditions tested in different
    places, in general each one can have its own associated
    loop invariant. Then the postcondition of the loop is

    (invariant1 and exitcond1) or (invariant2 and exitcond2) or ...

    If that gets you where you want to be, then you're
    home and dry.

    --
    Greg
  • Rhodri James at Oct 13, 2009 at 10:38 pm

    On Tue, 13 Oct 2009 22:59:04 +0100, Mensanator wrote:

    And I'm not saying John nor the OP should stop
    using what works for them. But there are certainly
    valid reasons for "don't use while True" to be
    on the "Best Practices" list.
    Unfortunately, some of them seem to be reasons from
    my point of view to put "*do* use while True" on the
    "Best Practices" list. Some of the constructs you
    seem to like ring big alarm bells with me, because
    I've found entirely too many bugs hidden by them.
    After all, how many times hve you put 'break'
    in a loop comprehension?
    How many times have you written 20-line list
    comprehensions? If the answer is more than zero,
    what on earth possessed you to think it was a
    good idea? :-)

    --
    Rhodri James *-* Wildebeest Herder to the Masses
  • Mensanator at Oct 14, 2009 at 1:26 am

    On Oct 13, 5:38?pm, "Rhodri James" wrote:
    On Tue, 13 Oct 2009 22:59:04 +0100, Mensanator wrote:
    And I'm not saying John nor the OP should stop
    using what works for them. But there are certainly
    valid reasons for "don't use while True" to be
    on the "Best Practices" list.
    Unfortunately, some of them seem to be reasons from
    my point of view to put "*do* use while True" on the
    "Best Practices" list. ?
    Really? Which ones?
    Some of the constructs you
    seem to like ring big alarm bells with me, because
    I've found entirely too many bugs hidden by them.
    For example?
    After all, how many times hve you put 'break'
    in a loop comprehension?
    How many times have you written 20-line list
    comprehensions? ?
    You mean something like this?

    p = [''.join
    ((c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19))
    for c0 in a for c1 in a for c2 in a for c3 in a for c4 in a for c5 in
    a for c6 in a for c7 in a for c8 in a for c9 in a for c10 in a for c11
    in a for c12 in a for c13 in a for c14 in a for c15 in a for c16 in a
    for c17 in a for c18 in a for c19 in a if (c1>c0) and (c2>c1) and
    (c3>c2) and (c4>c3) and (c5>c4) and (c6>c5) and (c7>c6) and (c8>c7)
    and (c9>c8) and (c10>c9) and (c11>c10) and (c12>c11) and (c13>c12) and
    (c14>c13) and (c15>c14) and (c16>c15) and (c17>c16) and (c18>c17) and
    (c19>c18)]

    Actually, I didn't write it, the computer did:

    v = ','.join(['c%s' % i for i in r0])
    f = ' '.join(['for c%s in a' % i for i in r0])
    i = ' and '.join(['(c%s>c%s)' % (j,j-1) for j in r1])
    e = ''.join(["p = [''.join((",v,")) ",f," if ",i,"]"])
    If the answer is more than zero,
    what on earth possessed you to think it was a
    good idea? :-)
    I didn't. It was a feasibility study. But that was
    in the days before itertools was upgraded to handle
    all the subsets of the Cartesian Product. No need for
    such silliness now. And itertools works better.
    --
    Rhodri James *-* Wildebeest Herder to the Masses
  • TerryP at Oct 14, 2009 at 4:20 am
    Mensanator, thank goodness that was generated :-P
  • Rhodri James at Oct 14, 2009 at 11:04 pm

    On Wed, 14 Oct 2009 02:26:17 +0100, Mensanator wrote:
    On Oct 13, 5:38?pm, "Rhodri James" wrote:
    On Tue, 13 Oct 2009 22:59:04 +0100, Mensanator <mensana... at aol.com>
    wrote:
    And I'm not saying John nor the OP should stop
    using what works for them. But there are certainly
    valid reasons for "don't use while True" to be
    on the "Best Practices" list.
    Unfortunately, some of them seem to be reasons from
    my point of view to put "*do* use while True" on the
    "Best Practices" list. ?
    Really? Which ones?
    Some of the constructs you
    seem to like ring big alarm bells with me, because
    I've found entirely too many bugs hidden by them.
    For example?
    Well, this one's always popular:

    done = False
    while not done:
    do_stuff()
    done = worry_about_stuff()
    do_more_stuff_at_great_length()
    done = worry_about_more_stuff()
    and_so_on()

    --
    Rhodri James *-* Wildebeest Herder to the Masses
  • Inhahe at Oct 19, 2009 at 6:32 pm
    On Mon, Oct 19, 2009 at 1:55 PM, inhahe wrote:
    On Sat, Oct 10, 2009 at 6:34 PM, Mensanator wrote:
    On Oct 10, 5:02?pm, kj wrote:
    In <01ccc46d-5ea9-4dfe-ba22-699c6b859... at v36g2000yqv.googlegroups.com>
    Mensanator <mensana... at aol.com> writes:
    In fact, if it were up to me, I would have made the fundamental
    looping construct something like

    repeat:
    ? ? ? ...
    ? ? ? if whatever():
    ? ? ? ? ? ?break
    ? ? ? ...
    So, the second set of '...' doesn't get executed.

    When I use

    while not done:
    ...
    if n==1: done = True
    ...

    the loop will actually complete (which is what
    I want) instead of aborting, like yours does.
    I just don't want the loop to execute again.
    Of course, this is why you would use "while not done" instead of "while
    True" or "repeat" in that situation, so i'm not sure what your contention
    is.

    Now, if I did a break before writing to the file,
    I would have to do all kinds of clean-up code
    outside the loop, code that would be run only
    if the exit were abnormal.
    This is why I propose an "until" keyword.

    until n == 1:
    ...

    i know some people don't like to add keywords "unnecessarily," but i really
    like to be able to express programs in a way that reflects what we actually
    mean, when there's a simple way this could be provided and it's a common use
    case.

    i recognize the problem with my solution is that "n" might not even be
    defined until somewhere in the loop after "until n == 1" is evaluated. this
    makes it a little weird, but it's not strictly a problem since the
    interpreter doesn't actually have to evaluate "n == 1" until the tail end of
    the loop.

    and made all the other looping constructs as syntatic sugar for
    this one.
    Luckily, it's not up to you.
    condescending and manipulative, as it merely begs the question of luckily
    for whom -- him, or you

    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20091019/31e035a5/attachment.htm>

Related Discussions

People

Translate

site design / logo © 2022 Grokbase