returning True, False or None

Discussion in 'Python' started by Jeremy Bowers, Feb 4, 2005.

  1. Yes, I see the smell, you are searching the list multiple times. You
    could bail out when you can:

    seenFalse = False
    for item in list:
    if item: return True
    if item is False: seenFalse = True
    if seenFalse:
    return False
    return None

    But I'd submit that if four item lists are your common case, that your
    original code is significantly easier to understand what it is doing. This
    can be alleviated with an appropriate comment on the chunk of code I gave
    you, though.
     
    Jeremy Bowers, Feb 4, 2005
    #1
    1. Advertisements

  2. Nope. To recall, my code was:

    seenFalse = False
    for item in list:
    if item: return True
    if item is False: seenFalse = True
    if seenFalse:
    return False
    return None

    So, turning that into a real function and not a sketch:

    Python 2.3.4 (#1, Jan 25 2005, 21:29:33)
    [GCC 3.4.3 (Gentoo Linux 3.4.3, ssp-3.4.3-0, pie-8.7.6.6)] on linux2
    Type "help", "copyright", "credits" or "license" for more information..... seenFalse = False
    .... for item in l:
    .... if item: return True
    .... if item is False: seenFalse = True
    .... if seenFalse:
    .... return False
    .... return None
    ....
    The defense rests, your honor. :)

    (I like the later use of "returnValue" and the reduce solution was cute
    and quite educational (very appropriate here). I deliberately eschewed
    fanciness, though.)
     
    Jeremy Bowers, Feb 4, 2005
    #2
    1. Advertisements

  3. I have lists containing values that are all either True, False or None,
    e.g.:

    [True, None, None, False]
    [None, False, False, None ]
    [False, True, True, True ]
    etc.

    For a given list:
    * If all values are None, the function should return None.
    * If at least one value is True, the function should return True.
    * Otherwise, the function should return False.

    Right now, my code looks like:

    if True in lst:
    return True
    elif False in lst:
    return False
    else:
    return None

    This has a light code smell for me though -- can anyone see a simpler
    way of writing this?

    STeVe
     
    Steven Bethard, Feb 4, 2005
    #3
  4. What about...:

    for val in lst:
    if val is not None:
    return val
    return None

    or the somewhat fancy/clever:

    for val in (x for x in lst if x is not None):
    return val
    return None


    Alex
     
    Alex Martelli, Feb 4, 2005
    #4
  5. "Steven Bethard"

    return max(lst)


    Raymond Hettinger
     
    Raymond Hettinger, Feb 4, 2005
    #5
  6. Jeremy Bowers

    Steve Holden Guest

    That code looks like a pretty solid implementation of the spec to me.
    There isn't a strict need for the last else, of course, which may be the
    smell you detect.

    If you wanted to get clever you could write something like

    for i in True, False:
    if i in lst:
    return i
    return False

    but frankly I think that's more obscure, and saves you pretty much nothing.

    regards
    Steve
     
    Steve Holden, Feb 4, 2005
    #6
  7. max(lst) ;-)

    Michael
     
    Michael Spencer, Feb 4, 2005
    #7
  8. Very clever! Thanks!

    Steve
     
    Steven Bethard, Feb 4, 2005
    #8
  9. Mick.
     
    Mick Krippendorf, Feb 4, 2005
    #9
  10. Alex Martelli said unto the world upon 2005-02-04 13:02:
    These don't do what the OP desired.

    ..>>> test_case = [False, True, True, True ]
    ..>>> def alexs_funct(lst):
    .. for val in lst:
    .. if val is not None:
    .. return val
    .. return None
    False

    But, by the 'spec', it ought return True.

    Best,

    Brian vdB
    A mere newbie, quite pleased with himself for finding a problem with
    'bot code -- next scheduled to occur mid 2011 :)
     
    Brian van den Broek, Feb 4, 2005
    #10
  11. too clever. boolean > None isn't guaranteed by the language specification:

    http://docs.python.org/ref/comparisons.html

    "... objects of different types always compare unequal, and are ordered consistently
    but arbitrarily. /.../ In the future, the comparison rules for objects of different types are
    likely to change. ..."

    </F>
     
    Fredrik Lundh, Feb 4, 2005
    #11
  12. Jeremy Bowers

    Peter Otten Guest

    An attempt to short-circuit if possible:

    def tristate(iterable):
    it = iter(iterable)
    for item in it:
    if item is not None:
    return item or True in it

    Not as elegant as max(), but makes me wonder whether a max() that accepts an
    additional upper_bound argument and returns upper_bound as soon as it
    encounters a value >= upper_bound would be worth the effort.

    Peter
     
    Peter Otten, Feb 4, 2005
    #12
  13. Yup. I thought about mentioning that for anyone who wasn't involved in
    the previous thread discussing this behavior, but I was too lazy. ;)
    Thanks for pointing it out again.

    This implementation detail was added in Python 2.1a1, with the following
    note[1]:

    "The outcome of comparing non-numeric objects of different types is
    not defined by the language, other than that it's arbitrary but
    consistent (see the Reference Manual). An implementation detail changed
    in 2.1a1 such that None now compares less than any other object. Code
    relying on this new behavior (like code that relied on the previous
    behavior) does so at its own risk."

    Steve

    [1] http://www.python.org/2.1/NEWS.txt
     
    Steven Bethard, Feb 4, 2005
    #13
  14. Jeremy Bowers

    Jeff Shannon Guest

    I'd modify this approach slightly...

    def tfn(lst):
    answer = None
    for item in lst:
    if item is True: return True
    if item is False: answer = False
    return answer

    But yeah, the original, straightforward way is probably enough clearer
    that I wouldn't bother with anything else unless lists might be long
    enough for performance to matter.

    Jeff Shannon
    Technician/Programmer
    Credit International
     
    Jeff Shannon, Feb 4, 2005
    #14
  15. "Steven Bethard"
    One more approach, just for grins:

    s = set(lst)
    return True in s or s == set([None]) and None


    Raymond Hettinger
     
    Raymond Hettinger, Feb 4, 2005
    #15
  16. I'm seeing a consistent problem in most of these approaches.
    Verbalized, the logic of the OP's original code reads as such:

    If True is in the list *at all*, return True.
    Otherwise, if False is in the list *at all*, return False.
    Otherwise, return None.

    So if we used Alex Martelli's code:
    and the list was:

    [ False , False , True , None ]

    False would be returned upon inspection of the first index, even
    though True was in fact in the list. The same is true of the code of
    Jeremy Bowers, Steve Juranich, and Jeff Shannon. As for Raymond
    Hettinger, I can't even be sure ;)

    The original OP's code, on the other hand, inadvertently searches
    through the list twice where once would have sufficed, causing a
    needless performance pitfall. The following applies the OP's initial
    logic while only iterating once:
    falseExists = False
    for item in items:
    if item is True:
    return True
    elif item is False and not falseExists:
    falseExists = True
    if falseExists:
    return False
    True

    It isn't elegant or clever, but it gets the job done :)
     
    Daniel Bickett, Feb 4, 2005
    #16
  17. I stand corrected :) My apologies.
     
    Daniel Bickett, Feb 4, 2005
    #17
  18. Then maybe like this:
    ... if e1 == None:
    ... return e2
    ... elif e2 == None:
    ... return e1
    ... else:
    ... return max(e1, e2)

    Mick.
     
    Mick Krippendorf, Feb 4, 2005
    #18
  19. Jeremy Bowers

    Jeff Shannon Guest

    Indeed. Similarly for mine, which was really just a slight transform
    of Jeremy's (setting a return variable directly, instead of setting a
    flag that's later used to decide what to return):
    .... answer = None
    .... for item in lst:
    .... if item is True: return True
    .... if item is False: answer = False
    .... return answer
    ....
    The noted logical flaw *has* been present in a number of proposed
    solutions, however.

    The key point to note is that one *must* examine the entire list
    *unless* you find a True; short-circuiting on False means that you may
    miss a later True.

    Jeff Shannon
    Technician/Programmer
    Credit International
     
    Jeff Shannon, Feb 4, 2005
    #19


  20. Or even shorter:
    ... result = None
    ... for item in items:
    ... if item:
    ... return True
    ... elif result is None and item is False:
    ... result = False
    ... return result


    Or like the Melmacians would do it:
    ... result = None
    ... for item in items:
    ... if result:
    ... raise StopIteration
    ... elif item is not None:
    ... result = item
    ... yield result

    Mick.
     
    Mick Krippendorf, Feb 5, 2005
    #20
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.