for-else

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • bearophileHUGS@lycos.com

    #1

    for-else

    So far in Python I've almost hated the 'else' of the 'for' loops:
    - I have problems to remember its meaning;
    - It gives me little problems when I later want to translate Python
    code to other languages (and you always have to translate long-lived
    code).
    - I have used it only once, so far.

    So so far I'd liked to see it removed from Python 3.0.

    But then this article:

    has shown me that my problems with the 'else' of the 'for' mostly come
    from just its bad naming. The converge language is yet another very
    Python-like language, and it uses a better naming (the word
    "exhausted" is long and has a complex spelling for non-English
    speakers, so it's not perfect):

    for ...:
    ...
    exhausted:
    ...
    broken:
    ...

    The meaning is explicit. While "else" seems to mean little there.
    So I may like something similar for Python 3.x (or the removal of the
    "else").

    Bye,
    bearophile
  • =?ISO-8859-1?Q?BJ=F6rn_Lindqvist?=

    #2
    Re: for-else

    On Tue, Mar 4, 2008 at 4:17 PM, Carl Banks <pavlovevidence @gmail.comwrote :
    for ...:
    ...
    exhausted:
    ...
    broken:
    ...
    >
    The meaning is explicit. While "else" seems to mean little there.
    So I may like something similar for Python 3.x (or the removal of the
    "else").
    >
    >
    I would not be opposed to this on its own merits, but there is a
    rationale behind the name "else". If you consider a for loop to be a
    rolled-up if...elif...els e statement (situations where this is
    reasonable tend to be the same ones were else would be useful), then
    the "else" clause would remain unchanged on the for loop.
    >
    For instance, if you have a (trivial) if...elif...els e like this:
    >
    if a == 0:
    do_task_0()
    elif a == 1:
    do_task_1()
    elif a == 2:
    do_task_2()
    else:
    do_default_task ()
    >
    You could roll it up into a for...else statement like this:
    >
    for i in range(3):
    if a == i:
    do_task[a]()
    else:
    do_default_task ()
    You forgot the break statement. The else suite will always be executed
    in this loop. Kind of proves bearophiles point, for-else is really
    tricky.


    --
    mvh Björn

    Comment

    • Tim Chase

      #3
      Re: for-else

      For instance, if you have a (trivial) if...elif...els e like this:
      >
      if a == 0:
      do_task_0()
      elif a == 1:
      do_task_1()
      elif a == 2:
      do_task_2()
      else:
      do_default_task ()
      >
      You could roll it up into a for...else statement like this:
      >
      for i in range(3):
      if a == i:
      do_task[a]()
      important "break" missing here...
      else:
      do_default_task ()

      or otherwise this code will do_task_i *and* do_default_task ()...

      -tkc


      Comment

      • Carl Banks

        #4
        Re: for-else

        On Mar 4, 10:55 am, "BJörn Lindqvist" <bjou...@gmail. comwrote:
        On Tue, Mar 4, 2008 at 4:17 PM, Carl Banks <pavlovevide... @gmail.comwrote :
        for ...:
        ...
        exhausted:
        ...
        broken:
        ...
        >
        The meaning is explicit. While "else" seems to mean little there.
        So I may like something similar for Python 3.x (or the removal of the
        "else").
        >
        I would not be opposed to this on its own merits, but there is a
        rationale behind the name "else". If you consider a for loop to be a
        rolled-up if...elif...els e statement (situations where this is
        reasonable tend to be the same ones were else would be useful), then
        the "else" clause would remain unchanged on the for loop.
        >
        For instance, if you have a (trivial) if...elif...els e like this:
        >
        if a == 0:
        do_task_0()
        elif a == 1:
        do_task_1()
        elif a == 2:
        do_task_2()
        else:
        do_default_task ()
        >
        You could roll it up into a for...else statement like this:
        >
        for i in range(3):
        if a == i:
        do_task[a]()
        else:
        do_default_task ()
        >
        You forgot the break statement. The else suite will always be executed
        in this loop. Kind of proves bearophiles point, for-else is really
        tricky.
        Ah ha, but that would have been a mistake with or without the else
        clause....


        Carl Banks

        Comment

        • Shane Geiger

          #5
          Re: for-else

          if a == 0:
          do_task_0()
          elif a == 1:
          do_task_1()
          elif a == 2:
          do_task_2()
          else:
          do_default_task ()
          The if-elif-else structure that calls functions (like that above) can be
          avoided with the code below:


          def foo0(): print 'foo0'
          def bar0(): print 'bar0'
          def foo1(): print 'foo1'
          def bar1(): print 'bar1'
          def do_default_task (): print 'do_default_tas k'

          do_task = { 0:foo0, 1:foo1, 2:bar0, 3:bar1, }

          a = 1

          # example of normal usage
          if a in do_task.keys(): do_task[a]()
          else: do_default_task ()

          # example of testing all functions in the dict as well as the default
          function
          for a in do_task.keys() + [8]: # 8 is a non-existent key in the do_task
          dict
          print "a is ",a,"and it gives this output:",
          if a in do_task.keys(): do_task[a]()
          else: do_default_task ()





          Carl Banks wrote:
          On Mar 4, 10:55 am, "BJörn Lindqvist" <bjou...@gmail. comwrote:
          >
          >On Tue, Mar 4, 2008 at 4:17 PM, Carl Banks <pavlovevide... @gmail.comwrote :
          >>
          >> for ...:
          >> ...
          >> exhausted:
          >> ...
          >> broken:
          >> ...
          >>>
          >> The meaning is explicit. While "else" seems to mean little there.
          >> So I may like something similar for Python 3.x (or the removal of the
          >> "else").
          >>>
          >> I would not be opposed to this on its own merits, but there is a
          >> rationale behind the name "else". If you consider a for loop to be a
          >> rolled-up if...elif...els e statement (situations where this is
          >> reasonable tend to be the same ones were else would be useful), then
          >> the "else" clause would remain unchanged on the for loop.
          >>>
          >> For instance, if you have a (trivial) if...elif...els e like this:
          >>>
          >> if a == 0:
          >> do_task_0()
          >> elif a == 1:
          >> do_task_1()
          >> elif a == 2:
          >> do_task_2()
          >> else:
          >> do_default_task ()
          >>>
          >> You could roll it up into a for...else statement like this:
          >>>
          >> for i in range(3):
          >> if a == i:
          >> do_task[a]()
          >> else:
          >> do_default_task ()
          >>>
          >You forgot the break statement. The else suite will always be executed
          >in this loop. Kind of proves bearophiles point, for-else is really
          >tricky.
          >>
          >
          Ah ha, but that would have been a mistake with or without the else
          clause....
          >
          >
          Carl Banks
          >
          This approach works well for me:



          def foo0(): print 'foo0'
          def bar0(): print 'bar0'
          def foo1(): print 'foo1'
          def bar1(): print 'bar1'

          def do_default_task (): print 'do_default_tas k'

          do_task = { 0:foo0, 1:foo1, 2:bar0, 3:bar1, }

          a = 1

          # example of normal usage
          if a in do_task.keys(): do_task[a]()
          else: do_default_task ()


          # example of testing
          for i in range(len(do_ta sk.keys)):
          if a in do_task.keys(): do_task[a]()
          else: do_default_task ()



          --
          Shane Geiger
          IT Director
          National Council on Economic Education
          sgeiger@ncee.ne t | 402-438-8958 | http://www.ncee.net

          Leading the Campaign for Economic and Financial Literacy

          Comment

          • Jeffrey Froman

            #6
            Re: for-else

            Carl Banks wrote:
            there is a
            rationale behind the name "else".  If you consider a for loop to be a
            rolled-up if...elif...els e statement
            This is an interesting angle. I've always considered "for/else" to be
            unintuitive, not because of "else", but because of the coupling with "for".
            Instead, I think of this as a "break/else" statement, and everything gels
            for me. The same applies to my comprehension of "while/else".

            I wonder how this came to be called "for/else" or "for-else". I haven't
            spotted that expression in the python docs yet.

            With whatever name, I find the construct quite elegant and regularly useful.


            Jeffrey


            Comment

            • Raymond Hettinger

              #7
              Re: for-else

              [BearOphile]
              So far in Python I've almost hated the 'else' of the 'for' loops
              FWIW, I'm very happy with for-else. Most of the time, you don't need
              it, but when you do, it beats the heck out of doing silly tricks with
              flags.

              The primary use case is searching a container:

              prep_tasks()
              for item in container:
              if predicate(item) :
              found_tasks()
              break
              else:
              not_found_tasks ()
              follow_up_tasks

              Raymond

              Comment

              • bearophileHUGS@lycos.com

                #8
                Re: for-else

                Raymond HettInger:
                FWIW, I'm very happy with for-else. Most of the time, you don't need
                it, but when you do, it beats the heck out of doing silly tricks with
                flags.
                I'd like it to be renamed to something more natural :-)

                Bye,
                bearophile

                Comment

                • Terry Reedy

                  #9
                  Re: for-else


                  <bearophileHUGS @lycos.comwrote in message
                  news:c4921e6c-119f-4306-8e89-c436c3cb6f6d@u6 9g2000hse.googl egroups.com...
                  | So far in Python I've almost hated the 'else' of the 'for' loops:
                  | - I have problems to remember its meaning;

                  Consider the following pseudoPython which you should understand:

                  label: loop
                  if cond:
                  do_something()
                  goto loop
                  else:
                  do_else()

                  We actually write the above as

                  while cond:
                  do_something()
                  else:
                  do_else()

                  Same meaning; do_else is executed when condition is false.

                  A for-loop is equivalent to a while loop with the condition 'iterator is
                  not exhausted'. So do_else when that condition is false -- the iterator is
                  exhausted.

                  Terry Jan Reedy



                  Comment

                  • Ben Finney

                    #10
                    Re: for-else

                    bearophileHUGS@ lycos.com writes:
                    But then this article:

                    has shown me that my problems with the 'else' of the 'for' mostly
                    come from just its bad naming. The converge language is yet another
                    very Python-like language, and it uses a better naming (the word
                    "exhausted" is long and has a complex spelling for non-English
                    speakers, so it's not perfect):
                    >
                    for ...:
                    ...
                    exhausted:
                    ...
                    broken:
                    ...
                    Rather than adding new keywords, I think the above would be better
                    spelled using the exception keywords::

                    for foo in bar_sequence:
                    # normal iteration
                    spam(foo)
                    if funky(foo):
                    break
                    except StopIteration, exc:
                    # the iterator stopped normally
                    eggs(exc)
                    else:
                    # the iterator exited abnormally, i.e. 'break'
                    sausage()
                    finally:
                    # always executed, even on 'break'
                    beans()

                    --
                    \ “[T]he question of whether machines can think [...] is about as |
                    `\ relevant as the question of whether submarines can swim.” |
                    _o__) —Edsger W. Dijkstra |
                    Ben Finney

                    Comment

                    • castironpi@gmail.com

                      #11
                      Re: for-else

                      That you could do yourself, CMIIW correct me if I'm wrong.

                      try:
                          for foo in iterex( bar_sequence ):
                              # normal iteration
                              spam(foo)
                              if funky(foo):
                                  break
                          except StopIterationEx , exc:
                              # the iterator stopped normally
                              eggs(exc)
                          else:
                              # the iterator exited abnormally, i.e. 'break'
                              sausage()
                          finally:
                              # always executed, even on 'break'
                              beans()
                      Qualm, except would be needed in every for-, and in one sense doesn't
                      obey the semantics of exceptions. The end of a finite list is not an
                      exceptional element-- it's not one. However generator semantics don't
                      yield finite sequences-- and finity is an exception, but for-loops
                      don't use infinite ones.

                      Makes it sound (*subj've) like I'm hacking by using for-loops..... or,
                      like sequencetype.__ iter__ is malformed. <staggered diminished chord>

                      Comment

                      • Troels Thomsen

                        #12
                        Re: for-else

                        >
                        The primary use case is searching a container:
                        >
                        prep_tasks()
                        for item in container:
                        if predicate(item) :
                        found_tasks()
                        break
                        else:
                        not_found_tasks ()
                        follow_up_tasks
                        >
                        I've found myself mimicing this again and again in c, and was pleased to
                        find it in python and use it regularely.
                        int i
                        for (i = 0 ; i < 10 ; ++i)
                        blah
                        if i == 10
                        not_found_tasks ()

                        The discussion of words is silly. My surprise about "else following a for
                        loop.... what the heck ...." lasted excactly as long as it takes to read
                        this sentence.


                        tpt


                        Comment

                        • bearophileHUGS@lycos.com

                          #13
                          Re: for-else

                          On Mar 5, 10:44 pm, "Troels Thomsen" <nej tak ...wrote:
                          The primary use case is searching a container:
                          >
                          prep_tasks()
                          for item in container:
                          if predicate(item) :
                          found_tasks()
                          break
                          else:
                          not_found_tasks ()
                          follow_up_tasks
                          >
                          I've found myself mimicing this again and again in c, and was pleased to
                          find it in python and use it regularely.
                          int i
                          for (i = 0 ; i < 10 ; ++i)
                          blah
                          if i == 10
                          not_found_tasks ()
                          >
                          The discussion of words is silly. My surprise about "else following a for
                          loop.... what the heck ...." lasted excactly as long as it takes to read
                          this sentence.
                          >
                          tpt

                          Comment

                          • egbert

                            #14
                            Re: for-else

                            The idea of the if-else is:
                            .. depending on some condition either do this or do something else,
                            .. don't do them both.

                            If you approach a loop-else with this same idea, you get:
                            .. depending on the loop conditions either do the loop,
                            .. or do something else, but not both.

                            However the loop-else really works more like this:
                            .. try to do the loop;
                            .. if it starts but is interrupted by a break,
                            .. then do something else as well.

                            So they are completely different beasts, and if you try to use
                            or explain the one according to the rules of the other one,
                            you put a serious strain on your synapses.

                            The explanation that the if-else and the loop-else
                            follow the same pattern, runs more or less like this:
                            .. all conditions to run the loop to its completion were met,
                            .. which means that the loop-condition is not met (any more),
                            .. which means that we must do something else.
                            For me that is orwellian logic: success is failure.

                            The loop-else mechanism is not an easy one:
                            earlier in this thread Carl Banks turned it into an either/or construct
                            by omitting the crucial break; Jeffrey Barish initially found
                            the loop-else surprising; Sion Arrowsmith found it comprehensible
                            only after some hard thinking (as in the last paragraph).

                            The culprit is of course the keyword, else.
                            The idea of an easy follow-up after a loop is a good one.
                            But we need other keywords, I think at least three of them:
                            .. skipped - the loop did not run at all
                            .. broken - the loop was interrupted (by a break)
                            .. exhausted - the loop ran to completion.
                            The last two as suggested by Laurence Tratt in his Convergence.
                            e
                            --
                            Egbert Bouwman - Keizersgracht 197 II - 1016 DS Amsterdam - 020 6257991
                            =============== =============== =============== =============== ============

                            Comment

                            • castironpi@gmail.com

                              #15
                              Re: for-else

                              The idea of the if-else is:
                              .  depending on some condition either do this or do something else,
                              .  don't do them both.
                              yes = the loop completed.

                              'else' isn't rechecking a piece of the loop, it's checking the loop.
                              Does it test successfully--- not the loop condition, the loop? What
                              is 'if a loop'? Make sense, I hold it does. (Holding is good--
                              something I can drop and give to someone else.) If 'else' gets hit, I
                              didn't do the loop.

                              Comment

                              Working...