14

Let's say I have a list with different values, like this:

[1,2,3,'b', None, False, True, 7.0]

I want to iterate over it and check that every element is not in list of some forbidden values. For example, this list is [0,0.0].

When I check if False in [0,0.0] I get True. I understand that python casts False to 0 here - but how I can avoid it and make this check right - that False value is not in [0,0.0]?

Sinister Beard
  • 3,570
  • 12
  • 59
  • 95
Paul
  • 6,641
  • 8
  • 41
  • 56
  • A list will be evaluated as True. Check [this question](http://stackoverflow.com/questions/1452489/evaluation-of-boolean-expressions-in-python) – Tomás Gonzalez Dowling Nov 16 '16 at 19:31
  • You should check the values individually, your methodology will only at best show you that something failed but won't tell you what, which would be you or your users next question. – DejaVuSansMono Nov 16 '16 at 19:31
  • 3
    You probably want to rethink the decision that led to a list containing `False` and `0` values that need to be treated differently. – chepner Nov 16 '16 at 19:37
  • 3
    @chepner actually you're right, bit I got this issue while solving kata from codewars. :) – Paul Nov 16 '16 at 20:36

3 Answers3

28

To tell the difference between False and 0 you may use is to compare them. False is a singleton value and always refers to the same object. To compare all the items in a list to make sure they are not False, try:

all(x is not False for x in a_list)

BTW, Python doesn't cast anything here: Booleans are a subclass of integers, and False is literally equal to 0, no conversion required.

kindall
  • 178,883
  • 35
  • 278
  • 309
11

You would want to use is instead of == when comparing.

y = 0
print y == False # True
print y is False # False

x = False
print x == False # True
print x is False # True
Michael Goodwin
  • 700
  • 6
  • 16
  • 2
    Good advice, but the original code doesn't contain `==`, it contains `in`. This is not a true answer to the question. – Mark Ransom Nov 16 '16 at 19:37
  • So the lesson learned is that for comparison of two logicals one should use `is` and `is not` instead of `==` – wander95 Nov 16 '16 at 19:43
  • @wander95 if you really need to know the difference between `False` and `0`, then yes. `True` and `1` too. Most of the time you don't need the distinction. `in` uses `==` and there's no way to change it. – Mark Ransom Nov 17 '16 at 03:11
0

Found a weird corner case on differentiating between 0 and False today. If the initial list contains the numpy version of False (numpy.bool_(False)), the is comparisons don't work, because numpy.bool_(False) is not False.

These arise all the time in comparisons that use numpy types. For example:

>>> type(numpy.array(50)<0) 
<class 'numpy.bool_'>

The easiest way would be to compare using the numpy.bool_ type: (np.array(50)<0) is (np.False_). But doing that requires a numpy dependency. The solution I came up with was to do a string comparison (working as of numpy 1.18.1):

str(numpy.bool_(False)) == str(False)

So when dealing with a list, a la @kindall it would be:

all(str(x) != str(False) for x in a_list)

Note that this test also has a problem with the string 'False'. To avoid that, you could exclude against cases where the string representation was equivalent to itself (this also dodges a numpy string array). Here's some test outputs:

>>> foo = False
>>> str(foo) != foo and str(foo) == str(False)
True

>>> foo = numpy.bool_(False)
>>> str(foo) != foo and str(foo) == str(False)
True

>>> foo = 0
>>> str(foo) != foo and str(foo) == str(False)
False

>>> foo = 'False'
>>> str(foo) != foo and str(foo) == str(False)
False

>>> foo = numpy.array('False')
>>> str(foo) != foo and str(foo) == str(False)
array(False)

I am not really an expert programmer, so there may be some limitations I've still missed, or a big reason not to do this, but it allowed me to differentiate 0 and False without needing to resort to a numpy dependency.

jranalli
  • 718
  • 1
  • 6
  • 14