bool([[None, None], [None, None]]) is True? Why?

I was wondering why

any([(None, None), (None, None)])
True
all([(None, None), (None, None)])
True
all([[None, None], [None, None]])
True
bool([[None, None], [None, None]])
True

given that

any([None, None, None])
False

It seems to me that the only way to check whether there exists one value, not None, is to flatten the list :

any(x for w in [(None, None), (None, None)] for x in w)
False

Is there a quicker way to do it?

The expression:

any([None, None, None])

tests each element in turn to see if it is a true value. So it tests:

None  # not a true value
None  # not a true value
None  # not a true value

and so returns False.

The expression:

any([(None, None), (None, None)])

likewise tests each element in turn to see if it is a true value. So it tests the first element:

(None, None)  # a true value

which is a true value, because it is a non-empty tuple. So it returns True.

The rules for what are considered true and false values are:

False values:

  • False (of course!)

  • zero numbers (0, 0.0, Fraction(0), Decimal(0) etc)

  • empty strings and byte-strings “” and b""

  • None

  • empty containers like (), , {}, set(), frozenset()

  • any object where len(obj) returns 0

  • any object where the special dunder method __bool__ returns False.

True values:

  • True (of course!)

  • all objects by default including:

  • non-zero numbers

  • non-empty strings and byte-strings

  • non-empty containers

  • any object where len(obj) returns a non-zero length

  • any object where the __bool__ dunder method returns True.

So it doesn’t matter that your tuple contains false objects like None, the fact that it contains something rather than nothing at all means that it counts as a true value.

3 Likes

As far as your second question about flattening the list, the answer remains the same as the answer I gave yesterday about flattening lists:

2 Likes