__contains__
__contains__(item) bool · Updated March 18, 2026 · Keywords The __contains__ method defines behavior for the membership test operators in and not in. When you use these operators, Python calls this method to determine whether an item exists in your object.
Signature
def __contains__(self, item) -> bool:
The method takes a single argument — the item to check for membership — and must return a boolean value (True or False).
How It Works
When Python evaluates item in container, it translates it to:
container.__contains__(item)
If __contains__ is not defined, Python falls back to iterating through the object using __iter__ and checking each item with the equality operator.
Basic Example
Here’s a simple container that delegates to an internal list:
class MyContainer:
def __init__(self, items):
self.items = items
def __contains__(self, item):
return item in self.items
container = MyContainer([1, 2, 3, 4, 5])
print(3 in container) # True
print(6 in container) # False
Custom Membership Logic
You can define membership rules that go beyond simple equality checks:
class EvenNumbers:
def __contains__(self, num):
return isinstance(num, int) and num % 2 == 0
evens = EvenNumbers()
print(4 in evens) # True
print(5 in evens) # False
print("a" in evens) # False
This container doesn’t store numbers — it defines membership mathematically.
Practical Use Cases
Case-Insensitive String Container
class CaseInsensitiveContainer:
def __init__(self, items):
self.items = [item.lower() for item in items]
def __contains__(self, item):
return item.lower() in self.items
fruits = CaseInsensitiveContainer(['Apple', 'Banana', 'Orange'])
print('apple' in fruits) # True
print('BANANA' in fruits) # True
print('pear' in fruits) # False
Range-Based Containment
class RangeContainer:
def __init__(self, ranges):
self.ranges = ranges
def __contains__(self, num):
return any(start <= num <= end for start, end in self.ranges)
ranges = RangeContainer([(1, 5), (10, 15), (20, 25)])
print(3 in ranges) # True
print(8 in ranges) # False
print(22 in ranges) # True
This efficiently handles discontinuous ranges without storing every possible value.
Performance Optimization
For large collections with frequent membership tests, use a set internally:
class OptimizedContainer:
def __init__(self, items):
self.items_set = set(items)
def __contains__(self, item):
return item in self.items_set
large_data = OptimizedContainer(range(1_000_000))
print(999999 in large_data) # True - O(1) lookup
print(-1 in large_data) # False - O(1) lookup
Fallback Behavior
If you don’t implement __contains__, Python tries __iter__ first, then falls back to __getitem__ with sequential index access. This is much slower for large collections.
See Also
__str__— String representation, another common dunder method__setitem__— Writing items to a container- Python docs: Emulating container types — Official documentation on container protocols