Python’s is
operator compares object identity, while ==
compares object values.
Python “is” operator
In Python, is
compares identity. In other words, it checks if two objects are the same object. It does not care if they have equal values, it cares if they have the same id in memory. This is why you often see is None
comparisons in Python; there is only one None
. On my machine, this is its id:
Here are some examples of how is
behaves:
1 is 1 # True, this is a primitive value
"a" is "a" # True, this is a primitive value
my_obj = {}
my_obj is my_obj # True, this is the same object
{} is {} # False, these are two different dicts
[] is [] # False, these are two different lists
a = 500
b = 500
a is b # False. Yep, False.
You might see the last example above and think: “What? 500 is not 500?” Nope, not if you’re using is
. At startup, Python caches—Python calls it “interning”—a set of commonly-used integers. Specifically, it pre-builds -5 to 256. Any integers outside of that range are constructed as they’re needed, and each construction will have a different location in memory. The same thing holds true for strings:
one = "justin"
two = "justin"
one is two # True. This seems ok..
three = "just in"
four = "just in"
three is four # False. Wait what?
The full explanation for why strings behave this way is a bit long for this post, but if you’re curious here’s a thorough stack overflow explanation. Tldr: When comparing strings or numbers, you should use ==
.
Python double equals ==
operator
Unless you’re comparing to None
, True
, or False
, ==
should be your default. Python’s ==
will compare the values being tested, not their identities. Let’s use the same examples as above:
1 == 1 # True
"a" == "a" # True
my_obj = {}
my_obj == my_obj # True
{} == {} # True
[] == [] # True
a = 500
b = 500
a == b # True
That’s better.
Under the hood, ==
uses an object’s __eq__
method, which typically looks something like this:
my_dict = {}
help(my_dict.__eq__)
"""
...
__eq__(self, value, /)
Return self==value.
...
"""
Instead of comparing memory locations—which is almost certainly not what you’re after—__eq__
compares the actual values.
__eq__
is one of many double-underscore or “dunder” methods in Python. There are tons of dunder methods built into common Python objects, this post has lots of details.
Conclusion
Unless you know for certain it’s safe to use is
, you should use ==
. If you’re comparing strings or numbers, you should always use ==
.