in in Python: Membership Operator Explained

Learn how to use Python's in operator for membership testing in lists, tuples, strings, sets, and dictionaries with syntax examples, performance tips, and best practices.

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
Output:
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
Output:
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)
Output:
True
False
False

Example 2: Case-insensitive check

text = "Hello, World!"
search = "world"

print(search.lower() in text.lower())  # Output: True
Output:
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
Output:
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")
Output:
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)
Output:
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
Output:
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
Output:
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
Output:
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
Output:
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")
Output:
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")
Output:
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']
Output:
['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!

Ready
main.py
Output Console 0 ms
// 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).