in Operator (Membership Test)
Python's in operator performs a membership test, checking whether an object is contained in a collection. It works with lists, tuples, sets, dicts, and strings, but the time complexity (speed) varies significantly depending on the collection type.
Syntax
# Check whether a value is contained in a collection (returns True or False).
value in collection
# Check whether a value is not contained in a collection (returns True or False).
value not in collection
# The most common use is with an if statement.
if value in collection:
# code to run when the value is found
# The in in a for statement means iteration, not membership testing.
for variable in iterable:
# code for each element
Operators and Methods
| Syntax | Notes |
|---|---|
| value in list | Scans the list from the beginning. Time complexity is O(n). |
| value in tuple | Scans the tuple from the beginning. Time complexity is O(n). |
| value in set | Uses a hash table to find the value. Time complexity is O(1). Suitable for searching large datasets. |
| key in dict | Works only on dictionary keys. Uses a hash table, so time complexity is O(1). |
| substring in string | Checks whether the substring is contained in the string. Time complexity is O(n*m). |
| value not in collection | Equivalent to not (value in collection), but more readable. |
Sample Code
Basic use of in with lists, tuples, and sets. This sample uses characters from KOF (The King of Fighters).
membership_basic.py
# Define a list of KOF fighters.
fighters_list = ["Kusanagi Kyo", "Yagami Iori", "Terry Bogard", "Shiranui Mai", "Andy Bogard"]
# Use in to check membership in a list.
print("Kusanagi Kyo" in fighters_list) # True
print("Leona Heidern" in fighters_list) # False
# Use not in to check non-membership.
print("Leona Heidern" not in fighters_list) # True
# The same syntax works with tuples.
forbidden_moves = ("Orochi Nagi", "Forbidden Move")
print("Orochi Nagi" in forbidden_moves) # True
# The same syntax works with sets (but search speed is O(1)).
rivals = {"Yagami Iori", "Leona Heidern", "Chris"}
print("Yagami Iori" in rivals) # True
print("Kusanagi Kyo" in rivals) # False
python3 membership_basic.py True False True True True False
Using in with a dictionary. When applied to a dict, in searches only the keys.
dict_membership.py
# Dictionary of KOF special moves.
special_moves = {
"Kusanagi Kyo": "Ura 108 Shiki: Orochi Nagi",
"Yagami Iori": "Forbidden 1201 Shiki: Yashiro Me",
"Terry Bogard": "Buster Wolf",
"Shiranui Mai": "Ryuuenbu",
}
# in searches dictionary keys (not values).
print("Kusanagi Kyo" in special_moves) # True (exists as a key)
print("Buster Wolf" in special_moves) # False (this is a value)
print("Leona" not in special_moves) # True (key does not exist)
# Use .values() to search values (O(n) linear scan).
print("Buster Wolf" in special_moves.values()) # True
# Use in to confirm a key exists before accessing it.
# Accessing a missing key raises KeyError, so checking with in is safer.
query = "Kusanagi Kyo"
if query in special_moves:
print(query + "'s special move:", special_moves[query])
else:
print("No data for " + query)
python3 dict_membership.py True False True True Kusanagi Kyo's special move: Ura 108 Shiki: Orochi Nagi
Using in with strings to search for substrings.
string_membership.py
# KOF character description text.
description = "Kusanagi Kyo is a practitioner of the Kusanagi ancient martial arts and wields flame."
# Use in to check whether a substring is present.
print("flame" in description) # True
print("Kusanagi" in description) # True
print("Yagami Iori" in description) # False
# Use not in for filtering.
names = ["Kusanagi Kyo", "Yagami Iori", "Terry Bogard", "Robert Garcia", "Ryo Sakazaki"]
# Extract fighters whose name does not contain a space (single-word names).
no_space = [name for name in names if " " not in name]
print(no_space) # []
# Case is distinguished.
move_name = "KUSANAGI"
print("kusanagi" in move_name) # False (case differs)
print("KUSANAGI" in move_name) # True
python3 string_membership.py True True False [] False True
Comparing search speed across collection types. Converting to a set is effective when searching large datasets.
performance_comparison.py
import time
# Create a large list of fighter names (100,000 items).
large_list = ["fighter_" + str(i) for i in range(100000)]
large_set = set(large_list) # Convert to a set.
target = "fighter_99999" # Search for a value near the end of the list.
# List search: O(n) (slow — scans from the beginning)
start = time.time()
for _ in range(1000):
result = target in large_list
elapsed_list = time.time() - start
# Set search: O(1) (fast — uses a hash table)
start = time.time()
for _ in range(1000):
result = target in large_set
elapsed_set = time.time() - start
print("List search time:", round(elapsed_list, 4), "seconds")
print("Set search time:", round(elapsed_set, 4), "seconds")
print("Set is about", round(elapsed_list / elapsed_set), "times faster")
python3 performance_comparison.py List search time: 1.7823 seconds Set search time: 0.0001 seconds Set is about 17823 times faster
Using __contains__ to define in behavior for a custom class.
contains_method.py
# Class representing a KOF team.
# Implementing __contains__ enables the in operator.
class KofTeam:
def __init__(self, name, members):
self.name = name
self.members = members
def __contains__(self, fighter_name):
# This method is called automatically when in is used.
return fighter_name in self.members
def __repr__(self):
return "KofTeam(" + self.name + ")"
# Define the Japan team.
japan_team = KofTeam("Japan Team", ["Kusanagi Kyo", "Nikaido Benimaru", "Daimon Goro"])
# The in operator calls __contains__.
print("Kusanagi Kyo" in japan_team) # True
print("Yagami Iori" in japan_team) # False
print("Yagami Iori" not in japan_team) # True
# Confirm the type.
print(type(japan_team)) # <class '__main__.KofTeam'>
python3 contains_method.py True False True <class '__main__.KofTeam'>
Common Mistakes
Common Mistake 1: in on a dict searches only keys
When in is used on a dictionary, it searches only the keys. To search values, use dict.values(). It is easy to assume that values can be searched directly with in.
ng_dict_value_search.py
# KOF special moves dictionary
special_moves = {
"Kusanagi Kyo": "Ura 108 Shiki: Orochi Nagi",
"Yagami Iori": "Forbidden 1201 Shiki: Yashiro Me",
"Terry Bogard": "Buster Wolf",
}
# Wrong: searching for a value with in returns False (keys are searched)
print("Buster Wolf" in special_moves) # False (not what was intended)
python3 ng_dict_value_search.py False
ok_dict_value_search.py
special_moves = {
"Kusanagi Kyo": "Ura 108 Shiki: Orochi Nagi",
"Yagami Iori": "Forbidden 1201 Shiki: Yashiro Me",
"Terry Bogard": "Buster Wolf",
}
# Use .values() to search values.
print("Buster Wolf" in special_moves.values()) # True
# Use .items() to search key-value pairs.
print(("Kusanagi Kyo", "Ura 108 Shiki: Orochi Nagi") in special_moves.items()) # True
python3 ok_dict_value_search.py True True
Common Mistake 2: List in is O(n), so be careful with large datasets
Searching a list with in scans from the beginning, so search time grows linearly with the number of elements (O(n)). When searching repeatedly or with a large number of elements, converting to a set provides a major speed improvement.
ng_large_list_search.py
import time
# Create a list of 100,000 items.
large_list = ["fighter_" + str(i) for i in range(100000)]
target = "fighter_99999"
# Searching a list repeatedly is slow.
start = time.time()
for _ in range(1000):
result = target in large_list
print("List search:", round(time.time() - start, 4), "seconds")
python3 ng_large_list_search.py List search: 1.7823 seconds
ok_set_search.py
import time
large_list = ["fighter_" + str(i) for i in range(100000)]
large_set = set(large_list) # Convert to a set.
target = "fighter_99999"
# After converting to a set, search is O(1) and very fast.
start = time.time()
for _ in range(1000):
result = target in large_set
print("Set search:", round(time.time() - start, 4), "seconds")
python3 ok_set_search.py Set search: 0.0001 seconds
Common Mistake 3: in on a string does substring matching
When in is used on a string, it performs substring matching. Code written expecting an exact match can unexpectedly return True for a partial match.
ng_string_partial.py
# The partial match behavior is easy to overlook.
fighter_name = "Kusanagi Kyo"
description = "Kusanagi Kyo is a practitioner of the Kusanagi martial arts."
# "Kusanagi" is part of description, so it returns True (partial match).
print("Kusanagi" in description) # True (partial match)
print("Kusanagi Kyo" in description) # True (also partial match)
# Easy to confuse with list membership (exact match).
names = ["Kusanagi Kyo", "Yagami Iori"]
print("Kusanagi" in names) # False (list uses exact match)
print("Kusanagi" in "Kusanagi Kyo") # True (string uses partial match)
python3 ng_string_partial.py True True False True
Use == for exact string comparison. Use in on a list when you want to check exact element membership.
Notes
The in operator is used for membership testing (containment checks). The in in a for statement means iteration, which is a completely different use from membership testing. Although the syntax looks similar, value in collection (returns True/False) and for variable in iterable (iterates over each element) serve entirely different purposes.
The difference in time complexity between collection types is important. List and tuple in is O(n) (linear search); set and dict key in is O(1) (hash lookup). When performing repeated searches over a large number of elements, converting the list to a set first provides a major speed improvement.
Using in on a dictionary searches only the keys. To search values, use value in dict.values(); to search key-value pairs, use (key, value) in dict.items(). See dict.keys() / values() / items() for details.
To support in on a custom class, implement __contains__(self, item). If __contains__ is not defined, Python falls back to iterating via __iter__, then to the sequence protocol via __getitem__. For more on dunder methods, see Dunder Methods (__str__ / __repr__ / __len__ etc.).
If you find any errors or copyright issues, please contact us.