Comparison and Membership Operators
00:00
A comparison operator is a binary operator that determines whether a particular relationship holds between the operands. For all built-in Python objects, comparison operators return either True
or False
.
00:15 However, Python allows you to create objects for which comparison operators return composite Boolean-type objects. A good example of this is the NumPy library.
00:26 When you apply some of the comparison operators to a NumPy array, you get a NumPy array of Boolean objects.
00:34 There are eight value comparison operators and there are two membership operators.
00:41 Let’s first take a look at the value comparison operators. There are eight of these. In the table, the first six are value comparison operators that have to do with the order relationship between the operands.
00:56
These are basic things like strictly less than (<
), or is greater than or equal to (>=
), and equal value (==
), or unequal value (!=
).
01:06 And then the last two operators are not just checking the value of the operands, but whether the operands are equal objects—so in other words, whether they point to the same memory address.
01:18 So, it’s definitely possible to have objects that have equal value, but not necessarily are equal objects.
01:28
Now, the equality operators can be applied to different data types. For example, Python is not going to return an error if, say, you compare the string that holds the digit 2 with the actual integer 2
. However, distinct data types will never compare equal, so if you do ask whether a string is equal to an integer, you’re going to get False
. Now, there is one important exception, which has to do with numeric data types.
01:59
If you compare the integer 0
with the float 0.0
, then you are going to get True
. In general, the situation is a little bit more delicate with the order operators—so the operators less than (<
), less than or equal to (<=
), greater than (>
), and greater or equal to (>=
). These cannot be applied with different data types.
02:21 The reason is because it’s not always clear how you can make an order comparison between different data types. In fact, things are a little bit more delicate than that because some objects don’t have a well-defined or canonical ordering. For example, how could you order, say, all possible dictionaries?
02:42 It’s not clear how you would go about doing this, and Python doesn’t support the order operators on dictionaries.
02:50
Now, in addition to the comparison operators, there are two membership operators, and these are in
and not in
. The operator x in a
checks whether x
is a member of a
, and x not in a
checks whether x
is not a member of a
. So not in
is just simply the negation of in
. Lists, tuples, sets, and dictionaries all support the membership operators. For a dictionary, membership is checked on the keys, not the values. For strings, membership is checked for the existence of a substring. And user-defined classes that define the .__contains__()
method or the .__iter__()
method support the membership operators, so you have to explicitly write down what it would mean for something to be contained in your object using the .__contains__()
method.
03:45 All right, let’s take a look at some examples of these operators in action.
03:50
Let’s start with some examples with the equal to (==
) and not equal to (!=
) operators. So 1 == 1
, that’s True
. And let’s try, is True
equal to the integer 1
?
04:05
So, we saw before that True
evaluates to 1
and 1
evaluates to True
. Now, the float 1.0
is equal to 1
.
04:17
And even the complex number 1 + 0j
, where the 0j
corresponds to the imaginary part—that’s also equal to 1
.
04:29
If you were performing a numerical computation and, say, something like 4/2
, that’s going to evaluate to the float 2.0
, and that is equal to the integer 2
.
04:42
So, those are good examples where distinct numeric types can actually equal in value. However, if you tried, say, the string that contains the integer 1
—if you compare that with the integer 1
, you’re going to get False
.
04:58
This is in contrast to some other languages where the string containing the integer 1
would be typecasted to the integer 1
. Python, on the other hand, doesn’t do that.
05:09
The general rule of thumb is that non-distinct objects will never be equal in value in Python. Now, some obvious ones. For instance, is the integer 2
equal to, say, the list of three elements?
05:22
Of course, this is False
. But complicated objects like a list—they can equal in value. So the list [1, 2, 3]
will equal the list with integers [1, 2, 3]
.
05:36
If we tried this with the sets that contain the integers 1
, 2
, 3
and so, for example, {3, 1, 2}
—
05:46
then in this case, you’re going to get True
. And this reflects the fact that sets don’t have a predetermined order, and so the container, or the set, that contains the elements 1
, 2
, 3
is the same thing as the container, or the set, that contains the elements 3
, 1
, 2
.
06:06
Let’s take a look at an example of using the equality operator with floating-point numbers, because things can be a little bit delicate. Well, let’s just first confirm that, say, 0.25 + 0.25
is equal in value to 0.5
, right?
06:22
No big surprise here. Let’s try now 0.2 + 0.1
and see if that is equal to 0.3
. So, we get False
, and it’s not a bug in Python.
06:38
The fact is is that not every real number has a exact binary representation. In particular, the value 0.1
, or the real number 0.1
, cannot be stored using a finite number of binary digits.
06:52
So, let’s see this with a bit more detail. Let x
equal 0.1
and let’s go ahead and see how Python is storing 0.1
. So let’s print the value of x
, this 0.1
, say using—I don’t know—let’s say 50 digits.
07:10
So let’s say x
and we’ll use 50
digits after the decimal sign (.
). So, this is how this 0.1
is being stored in memory, and so the fact is that 0.1
—when we use binary digits—the number of digits that are needed is infinite.
07:28 And so, of course, Python can’t store all these infinite digits and so there has to be some sort of truncation. And when that happens, we get a loss in accuracy.
07:37 This is something that you should definitely be aware of when you’re performing numerical computations and checking for equality when those numbers are floating-points numbers.
07:49
Now let’s try some examples that use the order type operators. So, for example, is 1.0
less than 3
? And of course, that’s True
. And we can also compare lists.
08:01
So, for example, the list with these two integers—is that greater or equal to the list that contains, I don’t know, a few fairly large integers, but starting off with 3
.
08:15
In this case, the list on the left, [4, 0]
, is greater than the list on the right, and so what we can infer from this is that Python is comparing elements at a time and whenever one of them is greater than the other, then Python will return True
. So in this case, [4, 0]
, 4
is being compared to 3
. And in this case, the list on the left is greater than the list on the right.
08:40
If we went ahead and changed that 3
to a 4.1
, then in this case we’re going to get False
.
08:50
Let’s look at a couple of examples with the order operators with distinct data types. So, for example, the list [1, 2, 3]
—is that less than the set containing the integers 4
, 5
, 6
? And in this case, we’re going to get a TypeError
.
09:07
The less than operator (<
) is not supported between instances of list
and set
. So I can’t use the order operators when the objects or the operands are a distinct type. However, you’re not going to get an error if you compare distinct numeric types.
09:25
So, is the float 1.0
less than 3
? And you’re going to get True
.
09:32
One important built-in data type that doesn’t support the order operators is the dictionary. Let’s go ahead and define a couple of dictionaries. Say, just maybe a couple of keys and values, and maybe this one will be 2
.
09:46
And then maybe we’ll define one more, call that one b
. And then here, we’ll put, say, 3
, and over here we’ll put 4
.
09:55
If you try to make the comparison “Is a
less than b
?” Python is going to return a TypeError
and the reason is because the Python dictionary doesn’t support less than (<
) or any of the other order type operators. And so even though these are two objects of the same type—in this case, they’re dictionaries—it’s not really clear how you would go about comparing them and Python decides not to do so. Now, even when it’s not necessarily clear how objects of the same type could be ordered—so for example, let’s say sets—Python does decide that you can order or that you can compare sets, but some of the results that you might get might be a little bit strange.
10:39
Let me show you an example. So let’s suppose the set containing the integers 1
, 2
, 3
, and let’s say, “Is this less than the set containing, say, the integers 4
, 5
, 6
?” Now in this case, we’re not going to get an error and Python returns False
.
10:57
All right, well, what if we ask Python or make the comparison “Is the set—now {4, 5, 6}
—is that less than the set {1, 2, 3}
?” Now, if it’s False
, that {1, 2, 3}
is less than the set containing 4
, 5
, 6
.
11:14
We would think that this would be True
, but Python actually returns False
. Now, the sets are not obviously equal, right? So the set {4, 5, 6}
is not equal to the set containing the integers 1
, 2
, 3
.
11:29
So none of these operators are going to return a True
value. If I try to say “Is {4, 5, 6}
, say, greater or equal to {1, 2, 3}
?” I’m also going to get False
.
11:41
So you can try the different cases in that you’re always going to get False
, and mathematically, really, this is a little bit awkward. I guess the only one where you’re going to get a True
statement is that these sets are certainly not equal, and so this is the one that returns True
.
11:59 Now, these are types of things that you’re not likely to use in your own code—you know, comparing sets and things like that—but at least you know that some of these comparisons can be made and it’s not necessarily clear whether they make any sense at all and whether they’re worth using.
12:16
Finally, let’s take a look at the is
and is not
operators. So to do this, let’s define a couple of lists. They’re going to have the same value, so the list containing the integers 1
, 2
, and 3
in that order.
12:30
So, these lists are definitely equal in value. They have the same integers and they are in the same order. However, they’re different objects in memory. Now, a way to see that these are really different objects in memory is to ask for the identity of these operators using the id()
function.
12:48
What this returns is the memory address of x
as it’s stored in memory. And if we do the same thing for y
, we’re going to get different addresses.
12:58
Essentially, this is what is
is going to check. And so “Is x
equal to y
?” We’re going to get False
because these memory addresses are distinct. Or in other words, both of these objects reference, or refer, to different objects in memory.
13:14 So these objects have the same value, but they are distinct objects.
13:21
Let’s go back to this list x
, so x
is storing the value [1, 2, 3]
, and let’s create a new copy of this list. Let’s call it z
. And of course, x
will have the same value as z
but something more than that happened. When you made the variable declaration of z
equal to x
, what z
actually stores is not just the same value as x
, but the same memory address that x
points to in memory.
13:48
So to see that explicitly, the ID of z
is the same as the ID of x
. And so if you use the is
operator with x
and z
, you’re going to get True
. And, of course, z is
—also—x
.
14:07
Let’s now a couple of examples of the in
and not in
operator. So, again, the in
operator is checking for membership. So, for example, is the integer 1
in the list [1, 2, 3]
?
14:20
And this is going to return True
. And then we can also do this, say, for sets. So, for example, let’s say "luigi"
and "mario"
and maybe "yoshi"
.
14:33
We can ask whether "luigi"
is in this set and, in this case, you’re going to get True
.
14:42
The in
operator is also supported by the string data type, and this will just simply check whether the string on the left of the operator is a substring of the string on the right. So let’s take the string containing these three names, "luigi mario yoshi"
, and then use the in
operator using the same string as we did above with the set, "luigi"
. We’re going to get True
.
15:08
But if we tried, for example, is "bowser"
in this string containing the names "luigi"
, "mario"
, and "yoshi"
, we’re going to get False
.
15:19
For dictionaries, the in
operator checks whether the object on the left is one of the keys of the dictionary. So, for example, let’s define a dictionary, say, with the key "a"
and value 1
, and then the second key "b"
, value 3
.
15:36
Then try using the in
operator. Is the key "c"
in the dictionary d
? And in this case, we get False
. Whereas if you try using, say, the string "b"
—that’s one of the keys in the dictionary—you’re going to get True
.
15:53
And if we instead use the not in
operator, is "b" not in d
? In this case, we’re going to get False
because we know that that key is one of the keys of the dictionary. All right! Well, that’s the rundown on the comparison operators in Python. In the next lesson, we’ll take a look at how you can chain these comparison operators.
Become a Member to join the conversation.