Demonstrate a case where == is True but is is False, and show the correct way to test for None.
Two lists with the same contents are equal but they are not identical. Equality asks whether two objects represent the same value. Identity asks whether two names refer to the very same object.
a = [1, 2]
b = [1, 2]
print(a == b) # True, the contents are the same
print(a is b) # False, they are two separate list objects
def describe(items):
for item in items:
if item is None:
return 'missing value found'
return 'nothing missing'
print(describe([1, None, 3])) # missing value found
For the None test, is None is not only the recommended form, it is the only form that is guaranteed to work. None is a singleton, so there is exactly one None object in the whole process and every reference to it points at that same object. That is what makes is None an identity test that always behaves in the same way. Writing == None happens to work by accident, because the equality of None is identity, but it is fragile. It relies on an implementation detail, and it will mislead anybody who has just been told that == means value comparison.
The rule that makes this clean is short. Use == when you mean the same value, and use is when you mean the same object, with one single exception. A None check is an identity test by design, so is None is exactly right there.
A useful defensive habit is the negated form. Write if value is not None: rather than if value:, because the second one is also True for an empty string, a zero, and an empty list. Those are all perfectly valid values that simply happen to be falsy.