The Python ‘in’ Operator

Introduction

The Python in operator checks for the inclusion of an item within a collection object. It returns True if the item is included and False otherwise. The in operator is versatile and can be used with many data types such as strings, lists, tuples, dictionaries, and sets.

Using the in Operator

The in operator checks whether an item is included within collection. If the item is included, in returns the Boolean value True, otherwise, it returns False.

Here is the basic syntax for the in operator:

item in collection

Example:

lst = [1, 2, 3]
print(2 in lst)
print(4 in lst)

Output:

True
False

The example above uses the in operator to check for the presence of the numbers 2 and 4 in the list, lst. The number 2 is in lst and 4 isn’t, therefore the output is True and False.

in with Strings

When used with strings, the in operator checks whether a substring exists within another string.

Example:

line = "One fish, two fish, red fish, blue fish"
word = "fish"

print(word in line) 
print("cat" in line)  

Output:

True
False

In the example above, "fish" in line is True because “fish” is a substring of the string line. Conversely, "cat" in line is False because “cat” is not a substring of line.

in with Dictionaries

When used with dictionaries, the in operator checks for the presence of a key within the dictionary.

Example:

student_grades = {"Alice": "A", "Bob": "B", "Charlie": "C"}

print("Alice" in student_grades)
print("David" in student_grades)

Output:

True
False

In the example above, "Alice" in student_grades is True because “Alice” is a key in the student_grades dictionary, while "David" in student_grades is False because “David” is not a key in the student_grades dictionary.

How the in Operator Works

The in operator works universally to determine inclusion within a collection, but every type of collection can, in its own way, define what inclusion means. As you’ve seen in the prior examples, for a list it means the presence an item in the list, for a string, the existence of a substring, and for a dictionary, the presence of a key.

Each collection type can define what it means for an item to be included in it by implementing the __contains__() method. The __contains__() method takes an item as a parameter and should be implemented to return True if the item is included and False if not.

__contains__() is a dunder method, which is a method whose name is surrounded by double underscores, and as such, by convention, is not meant to be used directly. The Python in operator uses it to determine inclusion.

Even though __contains__() is not meant to be used directly, we can still do so for illustrative purpose, as the next example shows.

Example:

line = "One fish, two fish, red fish, blue fish"
word = "fish"

print(line.__contains__(word)) 
print(line.__contains__("cat"))  

Output:

True
False

The example above uses the __contains__() method to test for substrings. It is otherwise identical to the previous substring example, which used the in operator instead.

If the contain methods is not implemented, it is still possible for in to work on objects that are iterable, as you’ll see in the next section.

in With Custom Objects

You can make any custom object, i.e. objects of classes you define, be compatible with the in operators. To do so, you can either implement the __contains__() method in your class, or make it into an iterable.

Implementing __contains__()

The example below defines a class that implements __contains__().

Example:

class MyCollection:
    def __init__(self, items):
        self.items = items
    
    def __contains__(self, item):
        return item in self.items

my_collection = MyCollection([1, 2, 3, 4, 5])

print(3 in my_collection) 
print(6 in my_collection)  

Output:

True
False

In the example above, the MyCollection class is a simple custom collection that uses an underlying list. The MyCollection class implements the __contains__() method (line 5), allowing the use of the in operator to check for the presence of items within any object of the MyCollection class.

Making the Class an Iterable

In the absence of __contains__(), in will still work on iterable objects. If you implement your object as an iterable without the __contains__() method, the in operator will use the iterable interface to search for the presence of a value within all the items in the collection.

Example:

class MyCollection:
    def __init__(self, items):
        self.items = items
        
    def __iter__(self):
        return iter(self.items)

my_collection = MyCollection([1, 2, 3, 4, 5])

print(3 in my_collection) 
print(6 in my_collection)  

Output:

True
False

The example above changes the MyCollection class from the previous example by removing the __contains__() method and adding an __iter__() method (line 5). __iter__() makes the object into an iterable by returning an iterator (line 6). The in operator still works despite the absence of __contains__() because this version of MyCollection is an iterable.

The not in Operator

The not in operator is the same as the in operator, except that it’s the exact Boolean opposite of it. It returns False if an item is included in a collection object, and True otherwise. Objects that support in automatically also support not in.

Example:

lst = [1, 2, 3]
print(2 not in lst)
print(4 not in lst)

Output:

False
True

Summary & Reference for the Python in Operator

The in operator checks for the inclusion of an item within a collection object, returning True if it is included and False otherwise.


The basic syntax for the in operator is:

item in collection
lst = [1, 2, 3]
print(2 in lst)  # --> True
print(4 in lst)  # --> False

In strings, the in operator checks for substrings.

line = "One fish, two fish, red fish, blue fish"
print("fish" in line)  # --> True
print("cat" in line)   # --> False

In dictionaries, the in operator checks for the presence of a key.

student_grades = {"Alice": "A", "Bob": "B", "Charlie": "C"}
print("Alice" in student_grades)  # --> True
print("David" in student_grades)  # --> False

The __contains__() method can be implemented by custom objects to support the in operator.

class MyCollection:
    def __init__(self, items):
        self.items = items
    
    def __contains__(self, item):
        return item in self.items

my_collection = MyCollection([1, 2, 3, 4, 5])
print(3 in my_collection)  # --> True
print(6 in my_collection)  # --> False

In the absence of __contains__(), making a custom object iterable also supports the in operator.

class MyCollection:
    def __init__(self, items):
        self.items = items
        
    def __iter__(self):
        return iter(self.items)

my_collection = MyCollection([1, 2, 3, 4, 5])
print(3 in my_collection)  # --> True
print(6 in my_collection)  # --> False

The not in operator is the Boolean opposite of in, returning True if the item is not in the collection and False otherwise.

lst = [1, 2, 3]
print(2 not in lst)  # --> False
print(4 not in lst)  # --> True