== is an equality test. It checks whether the right hand side and the left hand side are equal objects (according to their
is is an identity test. It checks whether the right hand side and the left hand side are the very same object. No methodcalls are done, objects can't influence the
is not) for singletons, like
None, where you don't care about objects that might want to pretend to be
None or where you want to protect against objects breaking when being compared against
First, let me go over a few terms. If you just want your question answered, scroll down to "Answering your question".
Object identity: When you create an object, you can assign it to a variable. You can then also assign it to another variable. And another.
>>> button = Button() >>> cancel = button >>> close = button >>> dismiss = button >>> print(cancel is close) True
In this case,
dismiss all refer to the same object in memory. You only created one
Button object, and all three variables refer to this one object. We say that
dismiss all refer to identical objects; that is, they refer to one single object.
Object equality: When you compare two objects, you usually don't care that it refers to the exact same object in memory. With object equality, you can define your own rules for how two objects compare. When you write
if a == b:, you are essentially saying
if a.__eq__(b):. This lets you define a
__eq__ method on
a so that you can use your own comparison logic.
Rationale: Two objects have the exact same data, but are not identical. (They are not the same object in memory.) Example: Strings
>>> greeting = "It's a beautiful day in the neighbourhood." >>> a = unicode(greeting) >>> b = unicode(greeting) >>> a is b False >>> a == b True
Note: I use unicode strings here because Python is smart enough to reuse regular strings without creating new ones in memory.
Here, I have two unicode strings,
b. They have the exact same content, but they are not the same object in memory. However, when we compare them, we want them to compare equal. What's happening here is that the unicode object has implemented the
class unicode(object): # ... def __eq__(self, other): if len(self) != len(other): return False for i, j in zip(self, other): if i != j: return False return True
unicode is definitely implemented more efficiently than this.
Rationale: Two objects have different data, but are considered the same object if some key data is the same. Example: Most types of model data
>>> import datetime >>> a = Monitor() >>> a.make = "Dell" >>> a.model = "E770s" >>> a.owner = "Bob Jones" >>> a.warranty_expiration = datetime.date(2030, 12, 31) >>> b = Monitor() >>> b.make = "Dell" >>> b.model = "E770s" >>> b.owner = "Sam Johnson" >>> b.warranty_expiration = datetime.date(2005, 8, 22) >>> a is b False >>> a == b True
Here, I have two Dell monitors,
b. They have the same make and model. However, they neither have the same data nor are the same object in memory. However, when we compare them, we want them to compare equal. What's happening here is that the Monitor object implemented the
class Monitor(object): # ... def __eq__(self, other): return self.make == other.make and self.model == other.model
When comparing to
None, always use
is not. None is a singleton in Python - there is only ever one instance of it in memory.
By comparing identity, this can be performed very quickly. Python checks whether the object you're referring to has the same memory address as the global None object - a very, very fast comparison of two numbers.
By comparing equality, Python has to look up whether your object has an
__eq__ method. If it does not, it examines each superclass looking for an
__eq__ method. If it finds one, Python calls it. This is especially bad if the
__eq__ method is slow and doesn't immediately return when it notices that the other object is
Did you not implement
__eq__? Then Python will probably find the
__eq__ method on
object and use that instead - which just checks for object identity anyway.
When comparing most other things in Python, you will be using