0

Can anybody please explain the behavior when is False preferred over None or None over False

1 in None or []  

Traceback (most recent call last):
  File "C:\ProgramData\Anaconda2\lib\site-packages\IPython\core\interactiveshell.py", line 2881, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-4-0f48647a1d09>", line 1, in <module>
    1 in None or []
TypeError: argument of type 'NoneType' is not iterable
1 in (None or [])
Out[5]: False

1 in (None or [1])
Out[6]: True

1 in [1] or None
Out[15]: True

1 in []
Out[17]: False

Below one returns None
1 in [] or None
**Returns None ** 

Why the below returns exception but for above None is returned

1 in None  
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda2\lib\site-packages\IPython\core\interactiveshell.py", line 2881, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-21-71e8d29ac0d2>", line 1, in <module>
    1 in None
TypeError: argument of type 'NoneType' is not iterable
Hariom Singh
  • 3,512
  • 6
  • 28
  • 52
  • 1
    It returns `None`, and IPython simply does not display it – vaultah Jul 17 '17 at 19:47
  • Then why this one doesn't return False 1 in None or [] – Hariom Singh Jul 17 '17 at 19:49
  • 3
    Please read [this](https://stackoverflow.com/questions/4477850/python-and-or-operators-return-value) page. – vaultah Jul 17 '17 at 19:50
  • How do you differentiate between None and Blank list ? – Hariom Singh Jul 17 '17 at 19:50
  • In case of 1 in None Traceback (most recent call last): File "C:\ProgramData\Anaconda2\lib\site-packages\IPython\core\interactiveshell.py", line 2881, in run_code exec(code_obj, self.user_global_ns, self.user_ns) File "", line 1, in 1 in None TypeError: argument of type 'NoneType' is not iterable – Hariom Singh Jul 17 '17 at 19:52
  • Because None is not an iterable, you need an iterable in the right side of the **in** operator, that's the reason you get that error TypeError: argument of type 'NoneType' is not iterable.The empty list is an iterable. – Kronen Jul 17 '17 at 19:59
  • @vaultah why down vote for this ? – Hariom Singh Jul 17 '17 at 21:36
  • @HariomSingh what makes you think I downvoted this question? Anyway, hover over the downvote button to see the most common reasons. – vaultah Jul 17 '17 at 21:41
  • @vaultah thanks ..:) since your comment was first .new to stack – Hariom Singh Jul 17 '17 at 21:44

4 Answers4

2

Let's look at each of those in turn:

1 in None or []    -> (1 in None) or [] -> (Error)
1 in (None or [])  -> 1 in []           -> False
1 in (None or [1]) -> 1 in [1]          -> True
1 in [1] or None   -> True or None      -> True
1 in []                                 -> False
1 in [] or None    -> False or None     -> None (not printed)

There are a few key points to understand that:

  • evaluation order is from left to right
  • x in y has precedence over y or z
  • x or y is evaluated as x if x else y
  • a None result is never printed in the interactive shell
tobias_k
  • 81,265
  • 12
  • 120
  • 179
2

(following some edits, here are some notes hopefully will help out with workaround / explanation)

 Note 1 - how to turn a None into a False with not not

Use the not operator to turn a None into a boolean True. Likewise, use not not to turn that None into a boolean False.

In [4]: a = 1 in [] or None

In [5]: print(a)
None

In [6]: print(not a)
True

In [7]: print(not not a)
False

 Note 2 - how to turn a None into a False with bool()

As per a comment below (by @tobias_k), we can actually turn a None straight into a False with the shorter code:

In [8]: print(bool(None))
False

 Note 3 - in operator only works on iterable data type

The in operator only works on data structure that is an iterable. We can check if a data structure is an iterable with the hasattr() function.

For example, a list, tuple, and range are all iterables:

In [31]: hasattr([], '__iter__')
Out[31]: True

In [32]: hasattr((), '__iter__')
Out[32]: True

In [33]: hasattr(range(0), '__iter__')
Out[33]: True

Since these are iterables, the in operator works (i.e. doesn't throw an error):

In [34]: 1 in []
Out[34]: False

In [35]: 1 in ()
Out[35]: False

In [36]: 1 in range(0)
Out[36]: False

Data types such as None, int, bool are not iterables:

In [40]: hasattr(None, '__iter__')
Out[40]: False

In [41]: hasattr(1, '__iter__')
Out[41]: False

In [42]: hasattr(True, '__iter__')
Out[42]: False

In [43]: hasattr(False, '__iter__')
Out[43]: False

The in operator would therefore throw an error against these non iterable types. e.g.

In [44]: 1 in None
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-44-71e8d29ac0d2> in <module>()
----> 1 1 in None

TypeError: argument of type 'NoneType' is not iterable

In [45]: 1 in 1
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-45-36200f7947c7> in <module>()
----> 1 1 in 1

TypeError: argument of type 'int' is not iterable

In [47]: 1 in False
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-47-0ba098e6e3c7> in <module>()
----> 1 1 in False

TypeError: argument of type 'bool' is not iterable

In [48]: 1 in True
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-48-5e7fb522bdca> in <module>()
----> 1 1 in True

TypeError: argument of type 'bool' is not iterable

 Note 4 - Understanding "or" operator

See how the followings are evalulated:

  • 1 in [] or None -> (1 in []) or None -> False or None -> (short circuit to return the non-false) None

  • 1 in [1, 2, 3] or None -> (1 in [1, 2, 3]) or None -> True or None -> (short circuit to return the non-false) True

  • 1 in None or [] -> (error!!!) or [] -> (short circuit to throw the) error!!!

  • 1 in None or [1, 2, 3] -> (error!!!) or [1, 2, 3] -> (short circuit to throw the) error!!!

Note that 1 in None always return an error. As explained in Note 3 previously, in operator only works on iterable, and None is not an iterable. Hence the error. (print out the above tests with print() to visualise it)

For the two erroneous cases you might want to consider adding some brackets to strengthen up the logic (as I've just read in @tobias_k 's answer). e.g.

  • change 1 in None or [] to 1 in (None or []) - this will evaluate to 1 in [] (bypassing the None) and should now return False (as expected)
  • change 1 in None or [1, 2, 3] to 1 in (None or [1, 2, 3]) - this will evaluate to 1 in [1, 2, 3] (again, bypassing the None) and should now return True (as expected)
Atlas7
  • 2,726
  • 4
  • 27
  • 36
  • 1
    This is something what I wanted to understand ...difference between None and False ..somewhat got it – Hariom Singh Jul 17 '17 at 20:12
  • @HariomSingh so turns out the error in your case is that the `in` only works against an iterable. i.e. `1 in []` would work (an empty `list` is still an iterable. This will rightfully return `False`, but a legitimate test!). Whereas `1 in None` would not work (because `None` is not an iterable. It will throw out an error.). I've edited my answer to add more info :) – Atlas7 Jul 17 '17 at 20:40
  • 1
    @Atlas7 Thanks friend for explaining in detail – Hariom Singh Jul 17 '17 at 21:45
  • @HariomSingh more than welcome. I've just added Note 4 in the answer for completeness - regarding the "or" operator. Hopefully this will shed more intuition! – Atlas7 Jul 17 '17 at 22:09
1

Print the result to see it:

>>> print(1 in [] or None)
None
  • None is not an iterable, you need an iterable in the right side of the in operator, that's the reason you get that error

    TypeError: argument of type 'NoneType' is not iterable.

    The empty list is an iterable. An iterable is an object capable of returning its members one at a time.

  • False is not preferred over None, nor None over False. This happens because that's how or operator works.

     >>> False or 5
     5
    

so

    >>> print(False or None)
    None
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Kronen
  • 369
  • 9
  • 23
0

Your code evaluates from left to right. So 1 in [] is False. So between False and None you get None.

>>> False or None
>>> False or False
False
>>> None or False
False

Maybe a little more clearly. This is how it evaluates it.

1 in [] or None

Step 1: Evaluate 1 in [] So we have False

Step 2: Compare False and None. Since the first element is False we just get the second value.

Cory Madden
  • 5,026
  • 24
  • 37