is
refers to identity, as in the identity of the object. ==
refers to equality, meaning do two (or the same) object(s) have the same value.
If I change the value of x, the value of y does not change, because they are not the same object, though they have the same value. If, on the other hand, I do
x = [1, 2, 3]
y = x
and then change something about either, I will be changing the underlying object that x and y are pointing to. These are labels (references) to underlying objects, not the objects themselves, and identity is not the same thing as value.
Edit:
Imagine we make a class called Person:
class Person(object):
def __init__(name):
self.name = name
There is more than one "Joe Smith" in the world. But they are not the same person. This is true in Python as well:
joe1 = Person("Joe Smith")
joe2 = Person("Joe Smith")
Their identities are different, because they are different objects, despite them carrying the same name value. We could create a comparison operator on them that checks if the name values are equivalent, so then joe1 == joe2
would be true, but joe1 is joe2
will never be the same.
This feature of Python is useful when you need to know if changing the state of an object is going to have consequences elsewhere. For example, if I pass a dictionary into a function, and change something about that dictionary it has changed everywhere. This is particularly important because Python passes function arguments around sometimes by value and sometimes by reference, and this can result in awkward to track down bugs (especially if you're new to Python):
>>> foo = {'bar': 'baz'}
>>> def changeit(z):
... z['spam'] = 'eggs'
...
>>> changeit(foo)
>>> foo
{'bar': 'baz', 'spam': 'eggs'}
>>> def changeit2(z):
... if z is foo:
... return "We don't want to mess with this, it affects global state."
... else:
... z['cro'] = 'magnon'
...
>>> changeit2(foo)
"We don't want to mess with this, it affects global state."