for: else: - any practical uses for the else clause?

Discussion in 'Python' started by metaperl.etc@gmail.com, Sep 26, 2006.

  1. Guest

    , Sep 26, 2006
    #1
    1. Advertising

  2. Guest

    metaperl> I'm wondering if anyone has ever found a practical use for the
    metaperl> else branch?

    Yeah, I use it from time to time:

    for foo in bar:
    if foo matches some condition:
    print "sail to tahiti!"
    break
    else:
    print "abandon ship!"

    Skip
    , Sep 26, 2006
    #2
    1. Advertising

  3. a écrit :
    > A very old thread:
    > http://groups.google.com/group/comp...7e?lnk=gst&q=for else&rnum=9#1542d2041257c47e
    >
    > discusses the optional "else:" clause of the for statement.
    >
    > I'm wondering if anyone has ever found a practical use for the else
    > branch?
    >


    I use it regularly in contructs like:

    for value in someList:
    if someCondition(value):
    print "a matching item was found"
    break
    else:
    print "no matching item"
    return False

    # ... continue with value

    --
    Amaury
    Amaury Forgeot d'Arc, Sep 26, 2006
    #3
  4. Fuzzyman Guest

    Amaury Forgeot d'Arc wrote:
    > a écrit :
    > > A very old thread:
    > > http://groups.google.com/group/comp...7e?lnk=gst&q=for else&rnum=9#1542d2041257c47e
    > >
    > > discusses the optional "else:" clause of the for statement.
    > >
    > > I'm wondering if anyone has ever found a practical use for the else
    > > branch?
    > >

    >
    > I use it regularly in contructs like:
    >
    > for value in someList:
    > if someCondition(value):
    > print "a matching item was found"
    > break
    > else:
    > print "no matching item"
    > return False
    >
    > # ... continue with value


    Me too...

    Same with while loops.

    Fuzzyman
    http://www.voidspace.org.uk/python/index.shtml

    >
    > --
    > Amaury
    Fuzzyman, Sep 26, 2006
    #4
  5. Bruno Desthuilliers, Sep 26, 2006
    #5
  6. Ben Sizer Guest

    wrote:
    > metaperl> I'm wondering if anyone has ever found a practical use for the
    > metaperl> else branch?
    >
    > Yeah, I use it from time to time:
    >
    > for foo in bar:
    > if foo matches some condition:
    > print "sail to tahiti!"
    > break
    > else:
    > print "abandon ship!"


    As a C++ programmer (which I'm sure undermines my argument before
    you've even read it...), this feels 'backwards' to me. Although I am no
    purist, the 'else' typically implies failure of a previous explicit
    condition, yet in this case, it's executed by default, when the
    previous clause was successfully executed. It would seem more natural
    if the else clause was triggered by 'bar' being empty, or even if the
    loop was explicitly broken out of, though I'm sure that would make the
    construct much less useful.

    --
    Ben Sizer
    Ben Sizer, Sep 27, 2006
    #6
  7. Ben Sizer <> wrote:
    > wrote:
    >> Yeah, I use it from time to time:
    >>
    >> for foo in bar:
    >> if foo matches some condition:
    >> print "sail to tahiti!"
    >> break
    >> else:
    >> print "abandon ship!"

    >
    >As a C++ programmer (which I'm sure undermines my argument before
    >you've even read it...), this feels 'backwards' to me. Although I am no
    >purist, the 'else' typically implies failure of a previous explicit
    >condition, yet in this case, it's executed by default, when the
    >previous clause was successfully executed. It would seem more natural
    >if the else clause was triggered by 'bar' being empty, [ ... ]


    It does:

    >>> for foo in []:

    .... print foo
    .... else:
    .... print 'else'
    ....
    else

    I think it's clearer to see by comparing while with if:

    if False:
    do nothing
    else:
    do something

    while False:
    do nothing
    else:
    do something

    and getting to the for behaviour from while is trivial.

    That said, I've not had much call for it and was kind of surprised to
    find myself writing a genuine for ... else the other week. But it was
    the obvious way to do the task at hand, and I was happy it was there.

    --
    \S -- -- http://www.chaos.org.uk/~sion/
    ___ | "Frankly I have no feelings towards penguins one way or the other"
    \X/ | -- Arthur C. Clarke
    her nu becomeþ se bera eadward ofdun hlæddre heafdes bæce bump bump bump
    Sion Arrowsmith, Sep 28, 2006
    #7
  8. metaperl Guest

    Actually right after posting this I came up with a great usage. I use
    meld3 for my Python based dynamic HTML generation. Whenever I plan to
    loop over a tree section I use a for loop, but if there is no data to
    iterate over, then I simply remove that section from the tree or
    populate it with a "no data" message.
    metaperl, Sep 29, 2006
    #8
  9. Klaas Guest

    metaperl wrote:
    > Actually right after posting this I came up with a great usage. I use
    > meld3 for my Python based dynamic HTML generation. Whenever I plan to
    > loop over a tree section I use a for loop, but if there is no data to
    > iterate over, then I simply remove that section from the tree or
    > populate it with a "no data" message.


    else: does not trigger when there is no data on which to iterate, but
    when the loop terminated normally (ie., wasn't break-ed out). It is
    meaningless without break.

    Python 2.4.3 (#1, Mar 29 2006, 15:37:23)
    [GCC 4.0.2 20051125 (Red Hat 4.0.2-8)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> for x in []:

    .... print 'nothing'
    .... else:
    .... print 'done'
    ....
    done

    -Mike
    Klaas, Sep 29, 2006
    #9
  10. Klaas Guest

    Klaas wrote:

    > else: does not trigger when there is no data on which to iterate, but
    > when the loop terminated normally (ie., wasn't break-ed out). It is
    > meaningless without break.


    Sorry, this was worded confusingly. "else: triggers when the loop
    terminates normally, not simply in the case that there is no iterated
    data".

    -Mike
    Klaas, Sep 29, 2006
    #10
  11. Mike Klaas Guest

    On 9/29/06, Johan Steyn <> wrote:
    > On 29 Sep 2006 11:26:10 -0700, Klaas <> wrote:
    >
    > > else: does not trigger when there is no data on which to iterate, but
    > > when the loop terminated normally (ie., wasn't break-ed out). It is
    > > meaningless without break.

    >
    > The else clause *is* executed when there is no data on which to iterate.
    > Your example even demonstrates that clearly:


    Yes--there is a missing "just" in that sentence.

    -Mike
    Mike Klaas, Sep 29, 2006
    #11
  12. On 9/29/06, Johan Steyn <> wrote:
    > I agree that it is meaningless without a break statement, but I still find
    > it useful when I want to determine whether I looped over the whole list or
    > not. For example, if I want to see whether or not a list contains an odd
    > number:
    >
    > for i in list:
    > if i % 2 == 1:
    > print "Found an odd number."
    > break
    > else:
    > print "No odd number found."
    >
    > Without the else clause I would need to use an extra variable as a "flag"
    > and check its value outside the loop:


    You can use generator comprehension:

    if (i for i in list if i % 2 == 1):
    print "Found an odd number."
    else:
    print "No odd number found."

    I *think* any() should also work:

    if any(i % 2 == 1 in list):
    ....

    And so on. For every use of the for/else clause there exists a better
    alternative. Which sums up my opinion about the construct -- if you
    are using it, there's something wrong with your code.

    --
    mvh Björn
    =?ISO-8859-1?Q?BJ=F6rn_Lindqvist?=, Sep 29, 2006
    #12
  13. wrote:
    > And so on. For every use of the for/else clause there exists a better
    > alternative. Which sums up my opinion about the construct -- if you
    > are using it, there's something wrong with your code.


    How do you transform this?

    height = 0
    for block in stack:
    if block.is_marked():
    print "Lowest marked block is at height", height
    break
    height += block.height
    else:
    raise SomeError("No marked block")

    -M-
    Matthew Woodcraft, Sep 29, 2006
    #13
  14. Paul Rubin Guest

    Matthew Woodcraft <> writes:
    > How do you transform this?
    >
    > height = 0
    > for block in stack:
    > if block.is_marked():
    > print "Lowest marked block is at height", height
    > break
    > height += block.height
    > else:
    > raise SomeError("No marked block")


    Untested:

    all_heights = [block.height for block in stack if block.is_marked()]
    if all_heights:
    height = sum(all_heights)
    else:
    raise SomeError("No marked block")

    Alternatively (lower memory usage for large list):

    all_heights = (block.height for block in stack if block.is_marked())
    try:
    height = all_heights.next()
    height += sum(all_heights)
    except StopIteration:
    raise SomeError("No marked block")
    Paul Rubin, Sep 29, 2006
    #14
  15. Paul Rubin enlightened us with:
    >> height = 0
    >> for block in stack:
    >> if block.is_marked():
    >> print "Lowest marked block is at height", height
    >> break
    >> height += block.height
    >> else:
    >> raise SomeError("No marked block")

    >
    > all_heights = [block.height for block in stack if block.is_marked()]
    > if all_heights:
    > height = sum(all_heights)
    > else:
    > raise SomeError("No marked block")
    >
    > Alternatively (lower memory usage for large list):
    >
    > all_heights = (block.height for block in stack if block.is_marked())
    > try:
    > height = all_heights.next()
    > height += sum(all_heights)
    > except StopIteration:
    > raise SomeError("No marked block")


    I must say that the for/else construct is a LOT more readable than the
    rewritten alternatives.

    Sybren
    --
    Sybren Stüvel
    Stüvel IT - http://www.stuvel.eu/
    Sybren Stuvel, Sep 30, 2006
    #15
  16. MonkeeSage Guest

    Sybren Stuvel wrote:
    > I must say that the for/else construct is a LOT more readable than the
    > rewritten alternatives.


    +1

    I just wish it had a more intuitive name like "after:" or "then:", as
    "else:" seems like a choice between the loop and the other block (but
    really the choice is between StopIteration and break).

    Regards,
    Jordan
    MonkeeSage, Sep 30, 2006
    #16
  17. Paul Rubin Guest

    Sybren Stuvel <> writes:
    > I must say that the for/else construct is a LOT more readable than the
    > rewritten alternatives.


    They are all pretty ugly. I prefer the genexp version with a
    hypothetical "is_empty" function:

    all_heights = (block.height for block in stack if block.is_marked())
    if is_empty(all_heights):
    raise SomeError("No marked block")
    heights = sum(all_heights)

    Python generators don't really work the right way for this though.

    I've been fooling around with Haskell, so these kinds of constructions
    seems more natural to me than explicit for loops.
    Paul Rubin, Sep 30, 2006
    #17
  18. Peter Otten Guest

    Sybren Stuvel wrote:

    > Paul Rubin enlightened us with:
    >>> height = 0
    >>> for block in stack:
    >>> if block.is_marked():
    >>> print "Lowest marked block is at height", height
    >>> break
    >>> height += block.height
    >>> else:
    >>> raise SomeError("No marked block")

    >>
    >> all_heights = [block.height for block in stack if block.is_marked()]
    >> if all_heights:
    >> height = sum(all_heights)
    >> else:
    >> raise SomeError("No marked block")
    >>
    >> Alternatively (lower memory usage for large list):
    >>
    >> all_heights = (block.height for block in stack if block.is_marked())
    >> try:
    >> height = all_heights.next()
    >> height += sum(all_heights)
    >> except StopIteration:
    >> raise SomeError("No marked block")

    >
    > I must say that the for/else construct is a LOT more readable than the
    > rewritten alternatives.


    I like

    def blocks_til_mark(stack):
    for block in stack:
    if block.is_marked():
    return
    yield block
    raise SomeError
    height = sum(block.height for block in blocks_til_mark(stack))

    Peter
    Peter Otten, Sep 30, 2006
    #18
  19. Peter Otten Guest

    Paul Rubin wrote:

    > Sybren Stuvel <> writes:
    >> I must say that the for/else construct is a LOT more readable than the
    >> rewritten alternatives.

    >
    > They are all pretty ugly. I prefer the genexp version with a
    > hypothetical "is_empty" function:
    >
    > all_heights = (block.height for block in stack if block.is_marked())
    > if is_empty(all_heights):
    > raise SomeError("No marked block")


    Such a function would have to rebind the generator:

    def check_empty(items):
    items = iter(items)
    try:
    first = items.next()
    except StopIteration:
    return False
    return chain([first], items)

    all_heights = check_empty(all_heights)
    if not all_heights:
    raise SomeError

    > heights = sum(all_heights)
    >
    > Python generators don't really work the right way for this though.


    You can make it work, but the result tends to be messy:

    from itertools import chain

    def raiseiter(exc, *args):
    raise exc(*args)
    yield None # unreachable
    def stop():
    raise StopIteration

    height = sum(block.height for block in chain(stack, raiseiter(SomeError)) if
    (not block.is_marked()) or stop())

    Peter
    Peter Otten, Sep 30, 2006
    #19
  20. Paul Rubin Guest

    Peter Otten <> writes:
    > I like
    >
    > def blocks_til_mark(stack):
    > for block in stack:
    > if block.is_marked():
    > return
    > yield block
    > raise SomeError
    > height = sum(block.height for block in blocks_til_mark(stack))


    Oh my, I realize now that I mis-read the original, and my examples
    were all wrong. Shows how the explicit loop isn't necessarily so
    clear ;-). Note that unlike the original, the loop above fails to set
    height = 0 in the case where the exception gets raise.

    I'd maybe just scan the stack twice. The rescan is needed only if
    there can be blocks with height <= 0. Otherwise, you can just raise
    SomeError if height == 0:

    height = sum(b.height for b in
    itertools.takewhile(lambda: not block.is_marked(), stack))

    if height == 0 and True not in (b.is_marked() for b in stack):
    raise SomeError
    Paul Rubin, Sep 30, 2006
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. bxbxb3

    "else process" clause

    bxbxb3, May 26, 2005, in forum: VHDL
    Replies:
    3
    Views:
    650
    combinational.logic $ soc-ip.com
    May 27, 2005
  2. cman

    Practical uses of XOR

    cman, Mar 12, 2007, in forum: C Programming
    Replies:
    37
    Views:
    2,019
    Keith Thompson
    Apr 26, 2007
  3. kj
    Replies:
    15
    Views:
    535
    Lawrence D'Oliveiro
    May 23, 2009
  4. A
    Replies:
    8
    Views:
    779
    James Kanze
    Aug 28, 2010
  5. Peter
    Replies:
    8
    Views:
    305
    Jorgen Grahn
    Dec 29, 2012
Loading...

Share This Page