'is' vs '==' in Python
Python has two very similar operators for checking whether two objects are equal. These two operators are
They are usually confused with one another because with simple data types, like
strings (which many people start learning Python with) they seem to do the same thing:
x = 5 s = "example" print("x == 5: " + str(x == 5)) print("x is 5: " + str(x is 5)) print("s == 'example': " + str(s == "example")) print("s is 'example': " + str(s is "example"))
Running this code will result in:
x == 5: True x is 5: True s == 'example': True s is 'example': True
This shows that
is return the same value (
True) in these cases. However, if you tried to do this with a more complicated structure:
some_list =  print("some_list == : " + str(some_list == )) print("some_list is : " + str(some_list is ))
This would result in:
some_list == : True some_list is : False
Here it becomes obvious that these operators aren't the same.
The difference comes from the fact that
ischecks for identity (of objects), while
==checks for equality (of value).
Here's another example that might clarify the difference between these two operators:
some_list1 =  some_list2 =  some_list3 = some_list1 print("some_list1 == some_list2: " + str(some_list1 == some_list2)) print("some_list1 is some_list2: " + str(some_list1 is some_list2)) print("some_list1 == some_list3: " + str(some_list1 == some_list3)) print("some_list1 is some_list3: " + str(some_list1 is some_list3))
This results in:
some_list1 == some_list2: True some_list1 is some_list2: False some_list1 == some_list3: True some_list1 is some_list3: True
As we can see,
some_list1 is equal to
some_list2 by value (they're both equal to
]), but they are not identical, meaning they aren't the same object, even though they have equal values.
some_list1 is both equal and identical to
some_list3 since they reference the same object in memory.
Mutable vs Immutable Data Types
While this part of the problem now might be clear (when we have named variables), another question might pop up:
==behave the same with unnamed
"example") but don't behave the same with unnamed lists (like
There are two kinds of data types in Python - mutable and immutable.
- Mutable data types are data types which you can "change" over time
- Immutable data types stay the same (have the same memory location, which is what
ischecks) once they are created
Mutable data types are:
set, and user-defined classes.
Immutable data types are:
Like many other languages Python handles immutable data types differently than mutable types, i.e. saves them in memory only once.
5 you use in your code is the exact same
5 you use in other places in your code, and the same goes for string literals you use.
If you use the string
"example" once, every other time you use
"example" it will be the exact same object. See this Note for further clarification.
We will be using a Python function called
id() which prints out a unique identifier for each object, to take a closer look at this mutability concept in action:
s = "example" print("Id of s: " + str(id(s))) print("Id of the String 'example': " + str(id("example")) + " (note that it's the same as the variable s)") print("s is 'example': " + str(s is "example")) print("Change s to something else, then back to 'example'.") s = "something else" s = "example" print("Id of s: " + str(id(s))) print("s is 'example': " + str(s is "example")) print() list1 =  list2 = list1 print("Id of list1: " + str(id(list1))) print("Id of list2: " + str(id(list2))) print("Id of : " + str(id()) + " (note that it's not the same as list1!)") print("list1 == list2: " + str(list1 == list2)) print("list1 is list2: " + str(list1 is list2)) print("Change list1 to something else, then back to the original () value.") list1 =  list1 =  print("Id of list1: " + str(id(list1))) print("list1 == list2: " + str(list1 == list2)) print("list1 is list2: " + str(list1 is list2))
Id of s: 22531456 Id of the String 'example': 22531456 (note that it's the same as the variable s) s is 'example': True Change s to something else, then back to 'example'. Id of s: 22531456 s is 'example': True Id of list1: 22103504 Id of list2: 22103504 Id of : 22104664 (note that it's not the same as list1!) list1 == list2: True list1 is list2: True Change list1 to something else, then back to the original () value. Id of list1: 22591368 list1 == list2: True list1 is list2: False
We can see that in the first part of the example,
s returned to the exact same
"example" object it was assigned to at the beginning, even if we change the value of
s in the meantime.
list does not return the same object whose value is
, but a whole new object is created, even if it has the same value as the first
If you run the code above, you are likely to get different IDs for the objects, but the equalities will be the same.
When are 'is' and '==' Used Respectively?
is operator is most commonly used when we want to compare the object to
None, and restricting its usage to this particular scenario is generally advised unless you really (and I do mean really) want to check whether two objects are identical.
is is generally faster than the
== operator because it simply checks for integer equality of the memory address.
Important note: The only situation when
is works exactly as might be expected is with singleton classes/objects (like
None). Even with immutable objects, there are situations where
is does not work as expected.
For example, for large
string objects generated by some code logic, or large
is can (and will) behave unpredictably. Unless you go through the effort of interning (i.e. making absolutely sure that only one copy of a
int/etc. exists), all the various immutable objects you plan to use,
is will be unpredictable.
The bottom line is: use
==in 99% of cases.
If two objects are identical they are also equal, and that the opposite isn't necessarily true.
Overriding '==' and '!=' Operators
is not behave in the same way as their "positive" counterparts do. Namely,
True if objects don't have the same value, while
is not returns
True if the objects are not stored in the same memory address.
One other difference between these two operators is that you can override the behavior of
!= for a custom class, while you can't override the behavior of
If you implement a custom
__eq()__ method in your class, you can change how the
!= operators behave:
class TestingEQ: def __init__(self, n): self.n = n # using the '==' to check whether both numbers # are even, or if both numbers are odd def __eq__(self, other): if (self.n % 2 == 0 and other % 2 == 0): return True else: return False print(5 == TestingEQ(1)) print(2 == TestingEQ(10)) print(1 != TestingEQ(2))
This results in:
False True True
!= check for equality (by value) and
is not check whether two objects are identical, i.e. checks their memory addresses.
However, avoid using
is unless you know exactly what you're doing, or when dealing with singleton objects like
None, since it can behave unpredictably.