Explain Codes LogoExplain Codes Logo

What is the difference between "is None" and "== None"

python
identity-vs-equality
numpy-arrays
best-practices
Anton ShumikhinbyAnton Shumikhin·Nov 20, 2024
TLDR

In Python, the is keyword is for an identity operator, and it confirms if two variables share identity. The identity operator for None is is None. This operator will return True if the variable being tested is, well (drumroll) - None!

Conversely, == serves as an equality operator, meaning it checks whether the value, or values, of two operands are equal. In the context of None, == None will return True if the value of the variable is None.

Take a quick look here:

var = None print(var is None) # outputs: I'm not just True, I'm True Pythonic way! print(var == None) # outputs: Yeah, I'm True as well, but less Pythonic, and kind of upset about it...

So align with the Pythonic principle of "there should be one-- and preferably only one --obvious way to do it" - use is None over == None for clarity, correctness, and code happiness.

Identity vs Equality: A Tale of Twins

Get ready for a rowdy ride through the lanes of Identity and Equality in Python.

The Risky Business of Overriding __eq__

Let's peek at the custom class A, it's a bit of a rebel.

class A: def __eq__(self, other): return True # I'm a rebel, I say I'm equal to EVERYTHING, even None! a = A() print(a == None) # outputs: True (I've fooled you! 😈) print(a is None) # outputs: False (But you can't fool "is"! 👮‍♂️)

In this wild case, a == None naively returns True because class A's __eq__ method dangerously declares equality with everything. However, a is None stands tough as the cool cop it is and corrects this reckless misrepresentation by returning False.

Watch out for unanticipated outcomes when using == None in the context of containers and collections:

lst = [None, None, None] print(lst == None) # outputs: False (I'm a list! Not a None!) print(lst[0] == None) # outputs: True (But my first element, yeah, that's None...)

Conversely,

print(lst is None) # outputs: False (See, I told you. I'm a list, not a None!)

Exception alert: numpy arrays

Handling numpy arrays? Act wisely! == None carries out element-wise comparison and returns an array of booleans, not a solitary value. Check if the entire array object is None using is None, like a boss.

import numpy as np arr = np.array([None, None, None]) print(arr == None) # outputs: [True True True] (Hey, we're all None here!) print(arr is None) # outputs: False (Don't believe my elements! As a whole, I'm not None!)

Beware the booby trap! Receiving an array in place of a Boolean could plant the seeds for peculiar bugs!

Pro tips:

  • Singletons (None, True, False): always use is.
  • Mutable data types (lists, dicts): use == content-wise, is identity-wise.
  • Numpy arrays: == None for element-wise, just handle with care!
  • To avoid false positives: always opt for is None

The art of breakthrough

Remember every rule has an exception. Certain frameworks or libraries may explicitly document different conventions. When you encounter these, put on your adaptation hat and march with local practices. Regardless, in pure Python realms, sticking to PEP 8's prudent counsel of using is for None comparisons will always be your safest bet.