The in operator is Python's membership operator that checks whether a value exists in a collection such as a list, tuple, string, set, or dictionary. It returns True if the value is found and False otherwise. This operator makes membership testing clean and readable.
What does the in operator do?
The in operator performs a membership test: it searches for a given value inside a collection and returns a Boolean result. The basic syntax is:
value in collection Here, value is what you're looking for, and collection can be any iterable object like a list, tuple, string, set, or dictionary (for dictionaries, in checks keys by default).
Using in with lists and tuples
Lists and tuples are the most common use cases for the in operator.
Example 1: Checking membership in lists
numbers = [1, 2, 3, 4, 5]
print(3 in numbers) # Output: True
print(10 in numbers) # Output: False
print(3 not in numbers) # Output: False True False False
Example 2: Checking membership in tuples
coordinates = (10, 20, 30)
print(20 in coordinates) # Output: True
print(50 in coordinates) # Output: False
print(50 not in coordinates) # Output: True True False True
For lists and tuples, Python uses a linear search algorithm, meaning it checks each element one by one until it finds a match or reaches the end. The time complexity is O(n), so larger collections take longer to search.
Using in with strings
When used with strings, the in operator checks for substring membership.
Example 1: Basic substring check
text = "Hello, World!"
print("World" in text) # Output: True
print("Python" in text) # Output: False
print("hello" in text) # Output: False (case-sensitive) True False False
Example 2: Case-insensitive check
text = "Hello, World!"
search = "world"
print(search.lower() in text.lower()) # Output: True True
String membership tests are case-sensitive. If you need case-insensitive checks, convert both strings to the same case. Substring searches in Python strings also have O(n) complexity in the worst case.
Using in with sets
Sets are optimized for membership testing. Because sets use hash tables internally, the in operator has an average time complexity of O(1).
Example 1: Fast membership check
allowed_users = {"alice", "bob", "charlie"}
print("alice" in allowed_users) # Output: True
print("dave" in allowed_users) # Output: False True False
Example 2: Performance optimization
# Slow for large lists
users = ["alice", "bob", "charlie"]
if "alice" in users:
print("Found")
# Fast - convert to set first
users_set = set(users)
if "alice" in users_set:
print("Found") Found Found
If you need to perform many membership checks, converting a list to a set first can dramatically improve performance.
Using in with dictionaries
When you use in with a dictionary, it checks whether a key exists (not values).
Example 1: Checking keys
user_ages = {"alice": 30, "bob": 25, "charlie": 35}
print("alice" in user_ages) # Output: True
print("dave" in user_ages) # Output: False
print(30 in user_ages) # Output: False (30 is a value, not a key) True False False
Example 2: Checking values
user_ages = {"alice": 30, "bob": 25, "charlie": 35}
# Check if a value exists
print(30 in user_ages.values()) # Output: True True
Example 3: Checking key-value pairs
user_ages = {"alice": 30, "bob": 25, "charlie": 35}
# Check if a key-value pair exists
print(("alice", 30) in user_ages.items()) # Output: True True
Dictionary membership tests for keys are also O(1) on average because dictionaries use hash tables.
The not in operator
Python also provides the not in operator, which returns True if the value is not found.
Example: Using not in
numbers = [1, 2, 3, 4, 5]
print(10 not in numbers) # Output: True
print(3 not in numbers) # Output: False True False
This is simply the logical negation of in, and it works with all the same data types.
Using in with custom objects
If you create your own classes, you can make them work with the in operator by implementing the __contains__() method.
Example: Custom collection class
class MyCollection:
def __init__(self, items):
self.items = items
def __contains__(self, item):
return item in self.items
my_list = MyCollection([1, 2, 3, 4, 5])
print(3 in my_list) # Output: True
print(10 in my_list) # Output: False True False
If your class does not define __contains__() but is iterable (implements __iter__()), Python will fall back to iterating through the collection to check membership.
Performance considerations
The performance of the in operator depends on the data type.
| Data Type | Time Complexity | Notes |
|---|---|---|
| List | O(n) | Linear search |
| Tuple | O(n) | Linear search |
| String | O(n) | Substring search |
| Set | O(1) average | Hash-based lookup |
| Dictionary | O(1) average | Hash-based lookup (keys only) |
For frequent membership checks on large collections, prefer sets or dictionaries over lists or tuples.
Common use cases
Use Case 1: Checking user permissions
admin_users = {"alice", "bob"}
if current_user in admin_users:
print("Access granted")
else:
print("Access denied") Access granted
Use Case 2: Validating input
valid_options = ["yes", "no", "maybe"]
user_input = input("Enter your choice: ")
if user_input in valid_options:
print("Valid choice")
else:
print("Invalid choice") Valid choice
Use Case 3: Filtering data
exclude_words = {"the", "is", "at", "which", "on"}
words = ["the", "quick", "brown", "fox"]
filtered = [word for word in words if word not in exclude_words]
print(filtered) # Output: ['quick', 'brown', 'fox'] ['quick', 'brown', 'fox']
Common mistakes and best practices
Mistake 1: Using in for range checks
# Not recommended for performance-critical code
if 5 in range(1, 10):
print("In range")
# Better: Use comparison operators
if 1 <= 5 < 10:
print("In range") Do not use in for numerical range checks like if 5 in range(1, 10): in performance-critical code; use comparison operators instead: if 1 <= 5 < 10:.
Practice 1: Convert lists to sets for frequent checks
# When checking membership in large lists repeatedly
large_list = [1, 2, 3, ...] # Many items
# Convert to set for faster lookups
large_set = set(large_list)
if item in large_set:
print("Found") When checking membership in large lists repeatedly, convert the list to a set first for much faster lookups.
Practice 2: Remember dictionary behavior
user_data = {"name": "Alice", "age": 30}
# in checks keys, not values
print("name" in user_data) # True
print("Alice" in user_data) # False
# To check values, use .values()
print("Alice" in user_data.values()) # True Remember that in checks keys in dictionaries, not values. Use .values() or .items() if you need to check values or key-value pairs.
Practice 3: Case sensitivity in strings
text = "Hello, World!"
# Case-sensitive check
print("hello" in text) # False
# Case-insensitive check
print("hello".lower() in text.lower()) # True String membership tests with in are case-sensitive; normalize case if needed.
Try it Yourself
Practice what you've learned by modifying the code below. Try changing the values and conditions to see different outputs!
// Click "Run Code" to see results
Related Topics
Frequently Asked Questions
What is the difference between 'in' and '==' in Python?
The in operator checks if a value exists in a collection (membership test), while == checks if two values are equal. For example, 3 in [1, 2, 3] returns True (membership), while [1, 2, 3] == [1, 2, 3] returns True (equality).
Does 'in' check keys or values in dictionaries?
The in operator checks keys in dictionaries by default. To check values, use value in dict.values(). To check key-value pairs, use (key, value) in dict.items().
Is 'in' case-sensitive when checking strings?
Yes, the in operator is case-sensitive when checking strings. "hello" in "Hello, World!" returns False. For case-insensitive checks, convert both strings to the same case: "hello".lower() in "Hello, World!".lower().
What is the performance difference between checking 'in' a list vs a set?
Checking membership in a list has O(n) time complexity (linear search), while checking in a set has O(1) average time complexity (hash-based lookup). For frequent membership checks on large collections, use sets for better performance.
Can I use 'in' with custom classes?
Yes, you can make custom classes work with the in operator by implementing the __contains__() method. If your class is iterable (implements __iter__()), Python will fall back to iteration if __contains__() is not defined.
What is the difference between 'in' and 'not in'?
The in operator returns True if a value is found in a collection, while not in returns True if a value is not found. not in is equivalent to not (value in collection).