In Python, the difference between the is statement and the == operator is:
- The is statement checks if two objects refer to the same object.
- The == operator checks if two objects have the same value.
>>> a = [1, 2, 3] >>> b = [1, 2, 3] >>> a is b False >>> a == b True
The variables a and b are different objects even though they have the same value. Thus comparing the values with the == operator returns True but checking if the variables refer to the same object results in False.
In this guide, you will learn what is the is statement, why it is important, and when you should use it.
Object Identity in Python
In Python, two objects with the same value does not imply the objects would be identical. Similar to how in real-life two persons with the same name does not imply they are the same person.
Whenever you create a Python object, Python stores it into a memory behind a specific memory address. Each object gets its own unique address in the memory.
You can check the memory address of any Python object using the built-in id() function. It returns an integer value that represents the memory address of the object.
>>> a = 1000 >>> id(a) 140053230323952
Now, if you create two objects with the same value, the objects still end up in different memory locations. You can verify this by checking the IDs of the objects.
>>> n1 = 1000 >>> n2 = 1000 >>> id(n1) 140053229510960 >>> id(n2) 140053229510768 >>> id(n1) == id(n2) False
Here you can see that the IDs are different.
In Python, there is a built-in mechanism for checking if the IDs of two objects are equal. This is the is statement.
The is Statement in Python
The is statement in Python checks if two objects are identical. In other words, it checks if two objects live in the same memory address, that is, if the objects have the same IDs.
The is statement returns True if the objects have the same ID, otherwise False.
With the is statement, you can replace this piece of code:
id(obj1) == id(obj2)
obj1 is obj2
From the previous chapter’s example, you can replace:
>>> id(n1) == id(n2) False
>>> n1 is n2 False
Now you already understand what is the difference between the equality operator == and the is statement in Python. Next, let’s take a look at how variables are just aliases to objects behind the scenes and how it affects the identity of the variables.
Variables Are Aliases in Python
You can think of a Python variable as a name attached to an object. A Python object can have many variables that refer to the same object. Each variable is thus like an alias for an object under the surface.
Let’s take a look at what assigning to a variable really means in Python and how it relates to the identities of the objects.
Python Object References
Have a look at this piece of code:
>>> print(1000) 1000
When you run it, the Python interpreter
- Creates an integer object.
- Assigns the value 1000 to it.
- Shows the value 1000 in the console.
But after this, there is no way for you to access that integer object anymore. It becomes orphaned. However, you can “store” this object into a variable.
But why is the word “store” in quotes?
In reality, you cannot really store objects into variables in Python. Instead, each variable acts as a reference to the actual memory address where the object lives.
To demonstrate this, let’s create a variable that stores an integer:
>>> num = 1000
This piece of code works such that it:
- Creates an integer object.
- Assigns the object a value of 1000.
- Creates an alias called num that can be used to refer to the new integer object.
So the variable num does not store the integer object. It only points to the memory address of that object.
Here is how it looks:
Now, whenever you access the variable num in your code, Python substitutes it with the int object that represents 1000.
>>> print(num) 1000
Example. Let’s create two list variables such that the second variable is set equal to the first one:
>>> a = [1, 2, 3] >>> b = a >>> a [1, 2, 3] >>> b [1, 2, 3]
Then, let’s change the first number of the list a to 1000 and check the contents of the lists:
>>> a = 1000 >>> a [1000, 2, 3] >>> b [1000, 2, 3]
Wait a minute! Changing the value of list a also changed the value of list b. Why does this happen?
As you already learned, a variable is a pointer to the memory location where the object actually lives. In the above example, you first create a variable a that points to a list:
>>> a = [1, 2, 3]
Then you create a new variable b that points to variable a:
>>> b = a
As you know, when you call a variable, you receive the object toward which the variable points. So the new variable b becomes an alias to the object referred by a.
In other words, now a and b both point to the same object behind the same memory address. Thus, if you modify the list, both a and b will change.
You can verify that the objects point to the same memory address by using the is statement:
>>> a is b True
Now you understand that Python variables are just references to actual objects.
To support understanding, let’s have a look at another example. This time, instead of dealing with list objects, let’s create an integer object that is referenced by variables a and b.
>>> a = 1000 >>> b = a
Now, let’s change the value in a:
>>> a = 2000
Now, let’s take a look at how variables a and b look like:
>>> a 2000 >>> b 1000
They are different! The variables a and b point to the same memory location so why did b not change when a changed?
The reason why this happens is you are actually not updating the original integer object. Instead, you are creating a completely new integer object that you assign to variable a.
As you remember, the variable assignment:
>>> a = 2000
Tells the Python interpreter to:
- Create a new integer object into a new memory address.
- Give it a value of 2000.
- Allow calling object with the name a.
In other words, assigning 2000 to the variable a makes it point to a new integer object that lives elsewhere in the memory. On the other hand, the variable b still points to the object where the variable a previously pointed to.
You can verify that the variables point to different objects by using the is statement:
>>> a is b False
By the way, an integer is an immutable object in Python. This example demonstrates it well. There is no way to modify an existing integer object. Instead, you always create a new object to “change” the value of the original one.
At this point, you know that variable assignment in Python creates a reference to an object.
With this in mind, you are not surprised by:
>>> a = 1000 >>> b = 1000 >>> id(a) 140053230323952 >>> id(b) 140053229510992 >> a is b False
Here the variables a and b refer to different objects in memory.
But what may be surprising is that repeating this experiment with smaller values the identities are the same:
>>> a = 10 >>> b = 10 >>> id(a) 9789280 >>> id(b) 9789280 >> a is b True
So why on earth does this happen?
When you run a Python program, the Python interpreter performs some optimizations under the hood. One of the optimizations is it creates objects that represent integers between -5 and 256. This is simply because those integer values are so commonly used.
Now, if you initialize an integer with a value between this range, the Python interpreter reuses a corresponding pre-built integer object instead of creating a new one. So a variable between -5 and 256 always references the same pre-built integer object.
If you create an integer outside of the range [-5, 256], you always create a new integer object.
This leads to inconsistencies when using the is statement over ==:
>>> a = 100 >>> b = 100 >>> a is b True >>> x = 1000 >>> y = 1000 >>> x is y False
Here a and b refer to the same address in memory due to the optimization described above. On the other hand, the values x and y are not optimized and thus point to different memory addresses.
To take home, never use the is statement to compare two variables whose values should be equal!
When Use “==” And When Use “is”
Most of the time, you should use == when making comparisons in Python.
A basic rule of thumb is to:
- Use the == to check if two objects have the same value.
- Use the is statement to check if two variables refer to the same object.
Let’s see some examples.
Equal Value Example
When you compare integers, strings, lists, sets, dictionaries, or other custom mutable objects, use the equality operator ==.
>>> a = [1, 2, 3] >>> b = [1, 2, 3] >>> if a == b: ... print("The list contents are the same") ... The list contents are the same
As a best practice, if you compare something with None, use the is statement. Do not use the equality operator ==.
>>> a = None >>> if a is not None: ... print("Not none") ... else: ... print("None found") ... None found
This is also recommended by the PEP8, the official style guide for Python:
Comparisons to singletons likePEP8
Noneshould always be done with
is not, never the equality operators.
This is because it is possible to write methods into custom classes that treat == None differently than you would expect.
>>> import numpy as np >>> a = np.zeros(5) >>> a == None array([False, False, False, False, False]) >>> a is None False
As you can see, comparing the array of zeros with None using the equality operator gives you an array of Booleans. However, comparing the array with None using the is statement gives you the expected results.
Class Instance Example
Usually, using the is statement is useful when you want to compare an object with something that should exist only once in the memory.
For example, comparing class instances can be smarter using the is statement. This is because you might want to make sure each class instance is unique in the program.
But why not use the == operator in that case?
Because you can override the behavior of == operator on custom objects.
For example, let’s say you have a User class in which you can compare users by their name. If the names of two users are the same, the == operator returns True. To do this, you need to override a special method called __eq__() that determines what happens when calling == between two objects.
Here is the code:
class User: def __init__(self, name): self.name = name def __eq__(self, otheruser): return self.name == otheruser.name
Now you can check if two users have the same name using the equality operator:
user1 = User("Alice") user2 = User("Alice") print(user1 == user2)
However, now it is not possible to check if there are two variables that point to the same user object. This is bad because you want to ensure that each user is unique in the program, and no two users refer to the same object.
To overcome this issue, use is to check if the users are the same:
user1 = User("Alice") user2 = User("Alice") print(user1 is user2)
As you can see, even though the names of the users are the same, the is statement realizes these variables refer to different user objects.
To conclude, in this case, using the is statement produces more reliable results than the equality operator ==. Using the is statement you can reliably be sure if there is only one user1 in the program.
Today you learned what is the difference between the is statement and the equality operator == in Python.
To recap, the is statement checks if two objects point to the same object in memory, that is if they have the same IDs.
The equality operator == checks if two objects have the same value. But the equality operator does not care if the objects are actually the same object with the same IDs.
Thanks for reading.