Python’s in and not in operators allow you to quickly determine if a given value is or isn’t part of a collection of values. This type of check is common in programming, and it’s generally known as a membership test in Python. Therefore, these operators are known as membership operators.
In this tutorial, you’ll learn how to:
- Perform membership tests using the
inandnot inoperators - Use
inandnot inwith different data types - Work with
operator.contains(), the equivalent function to theinoperator - Provide support for
inandnot inin your own classes
To get the most out of this tutorial, you’ll need basic knowledge of Python, including built-in data types, such as lists, tuples, ranges, strings, sets, and dictionaries. You’ll also need to know about Python generators, comprehensions, and classes.
Source Code: Click here to download the free source code that you’ll use to perform membership tests in Python with in and not in.
Getting Started With Membership Tests in Python
Sometimes you need to find out whether a value is present in a collection of values or not. In other words, you need to check if a given value is or is not a member of a collection of values. This kind of check is commonly known as a membership test.
Arguably, the natural way to perform this kind of check is to iterate over the values and compare them with the target value. You can do this with the help of a for loop and a conditional statement.
Consider the following is_member() function:
>>> def is_member(value, iterable):
... for item in iterable:
... if value is item or value == item:
... return True
... return False
...
This function takes two arguments, the target value and a collection of values, which is generically called iterable. The loop iterates over iterable while the conditional statement checks if the target value is equal to the current value. Note that the condition checks for object identity with is or for value equality with the equality operator (==). These are slightly different but complementary tests.
If the condition is true, then the function returns True, breaking out of the loop. This early return short-circuits the loop operation. If the loop finishes without any match, then the function returns False:
>>> is_member(5, [2, 3, 5, 9, 7])
True
>>> is_member(8, [2, 3, 5, 9, 7])
False
The first call to is_member() returns True because the target value, 5, is a member of the list at hand, [2, 3, 5, 9, 7]. The second call to the function returns False because 8 isn’t present in the input list of values.
Membership tests like the ones above are so common and useful in programming that Python has dedicated operators to perform these types of checks. You can get to know the membership operators in the following table:
| Operator | Description | Syntax |
|---|---|---|
in |
Returns True if the target value is present in a collection of values. Otherwise, it returns False. |
value in collection |
not in |
Returns True if the target value is not present in a given collection of values. Otherwise, it returns False. |
value not in collection |
As with Boolean operators, Python favors readability by using common English words instead of potentially confusing symbols as operators.
Note: Don’t confuse the in keyword when it works as the membership operator with the in keyword in the for loop syntax. They have entirely different meanings. The in operator checks if a value is in a collection of values, while the in keyword in a for loop indicates the iterable that you want to draw from.
Like many other operators, in and not in are binary operators. That means you can create expressions by connecting two operands. In this case, those are:
- Left operand: The target value that you want to look for in a collection of values
- Right operand: The collection of values where the target value may be found
The syntax of a membership test looks something like this:
value in collection
value not in collection
In these expressions, value can be any Python object. Meanwhile, collection can be any data type that can hold collections of values, including lists, tuples, strings, sets, and dictionaries. It can also be a class that implements the .__contains__() method or a user-defined class that explicitly supports membership tests or iteration.
If you use the in and not in operators correctly, then the expressions that you build with them will always evaluate to a Boolean value. In other words, those expressions will always return either True or False. On the other hand, if you try and find a value in something that doesn’t support membership tests, then you’ll get a TypeError. Later, you’ll learn more about the Python data types that support membership tests.
Now that you know what membership operators are, it’s time to learn the basics of how they work.
Python’s in Operator
To better understand the in operator, you’ll start by writing some small demonstrative examples that determine if a given value is in a list:
>>> 5 in [2, 3, 5, 9, 7]
True
>>> 8 in [2, 3, 5, 9, 7]
False
The first expression returns True because 5 appears inside your list of numbers. The second expression returns False because 8 isn’t present in the list.
According to the in operator documentation, an expression like value in collection is equivalent to the following code:
any(value is item or value == item for item in collection)
The generator expression wrapped in the call to any() builds a list of the Boolean values that result from checking if the target value has the same identity or is equal to the current item in collection. The call to any() checks if any one of the resulting Boolean values is True, in which case the function returns True. If all the values are False, then any() returns False.
Python’s not in Operator
The not in membership operator does exactly the opposite. With this operator, you can check if a given value is not in a collection of values:
>>> 5 not in [2, 3, 5, 9, 7]
False
>>> 8 not in [2, 3, 5, 9, 7]
True
In the first example, you get False because 5 is in [2, 3, 5, 9, 7]. In the second example, you get True because 8 isn’t in the list of values. This negative logic may seem like a tongue twister. To avoid confusion, remember that you’re trying to determine if the value is not part of a given collection of values.
Note: The not value in collection construct works the same as the value not in collection one. However, the former construct is more difficult to read. Therefore, you should use not in as a single operator instead of using not to negate the result of in.
With this quick overview of how membership operators work, you’re ready to go to the next level and learn how in and not in work with different built-in data types.
Using in and not in With Different Python Types
All built-in sequences—such as lists, tuples, range objects, and strings—support membership tests with the in and not in operators. Collections like sets and dictionaries also support these tests. By default, membership operations on dictionaries check whether the dictionary has a given key or not. However, dictionaries also have explicit methods that allow you to use the membership operators with keys, values, and key-value pairs.
In the following sections, you’ll learn about a few particularities of using in and not in with different built-in data types. You’ll start with lists, tuples, and range objects to kick things off.
Lists, Tuples, and Ranges
So far, you’ve coded a few examples of using the in and not in operators to determine if a given value is present in an existing list of values. For these examples, you’ve explicitly used list objects. So, you’re already familiar with how membership tests work with lists.
With tuples, the membership operators work the same as they would with lists:
>>> 5 in (2, 3, 5, 9, 7)
True
>>> 5 not in (2, 3, 5, 9, 7)
False
There are no surprises here. Both examples work the same as the list-focused examples. In the first example, the in operator returns True because the target value, 5, is in the tuple. In the second example, not in returns the opposite result.
For lists and tuples, the membership operators use a search algorithm that iterates over the items in the underlying collection. Therefore, as your iterable gets longer, the search time increases in direct proportion. Using Big O notation, you’d say that membership operations on these data types have a time complexity of O(n).
If you use the in and not in operators with range objects, then you get a similar result:
>>> 5 in range(10)
True
>>> 5 not in range(10)
False
>>> 5 in range(0, 10, 2)
False
>>> 5 not in