collections.abc¶
The collections.abc module provides abstract base classes for container types. These help you create classes that work with Python's built-in operations.
Common Abstract Base Classes¶
from collections.abc import Sequence, Mapping, Set
# Check if object is a Sequence
list_obj = [1, 2, 3]
print(isinstance(list_obj, Sequence)) # True
tuple_obj = (1, 2, 3)
print(isinstance(tuple_obj, Sequence)) # True
dict_obj = {'a': 1}
print(isinstance(dict_obj, Mapping)) # True
set_obj = {1, 2, 3}
print(isinstance(set_obj, Set)) # True
Creating a Custom Sequence¶
from collections.abc import Sequence
class CustomList(Sequence):
def __init__(self, data):
self._data = list(data)
def __getitem__(self, index):
return self._data[index]
def __len__(self):
return len(self._data)
custom = CustomList([10, 20, 30])
print(custom[0]) # 10
print(len(custom)) # 3
print(20 in custom) # True
print(list(custom)) # [10, 20, 30]
# Supports iteration
for item in custom:
print(item)
Creating a Custom Mapping¶
from collections.abc import Mapping
class DictWrapper(Mapping):
def __init__(self, data):
self._data = dict(data)
def __getitem__(self, key):
return self._data[key]
def __iter__(self):
return iter(self._data)
def __len__(self):
return len(self._data)
wrapper = DictWrapper({'a': 1, 'b': 2})
print(wrapper['a']) # 1
print(len(wrapper)) # 2
print('b' in wrapper) # True
print(dict(wrapper)) # {'a': 1, 'b': 2}
Creating a Custom Set¶
from collections.abc import Set
class UniqueList(Set):
def __init__(self, data):
self._data = set(data)
def __contains__(self, item):
return item in self._data
def __iter__(self):
return iter(self._data)
def __len__(self):
return len(self._data)
unique = UniqueList([1, 2, 2, 3, 3, 3])
print(len(unique)) # 3
print(2 in unique) # True
print(unique & UniqueList([2, 3, 4])) # {2, 3} - set operations work!
Iterator and Iterable¶
from collections.abc import Iterator, Iterable
class CountUp(Iterable):
def __init__(self, max):
self.max = max
def __iter__(self):
return CountUpIterator(self.max)
class CountUpIterator(Iterator):
def __init__(self, max):
self.current = 1
self.max = max
def __iter__(self):
return self
def __next__(self):
if self.current <= self.max:
result = self.current
self.current += 1
return result
else:
raise StopIteration
counter = CountUp(3)
for num in counter:
print(num) # 1, 2, 3
Callable¶
from collections.abc import Callable
# Check if something is callable
print(callable(print)) # True
print(callable(int)) # True
print(callable([])) # False
def my_function():
pass
print(isinstance(my_function, Callable)) # True
class CallableClass:
def __call__(self):
return "Called!"
obj = CallableClass()
print(isinstance(obj, Callable)) # True
print(obj()) # Called!
Container¶
from collections.abc import Container
class AllowList(Container):
def __init__(self, allowed_items):
self._allowed = set(allowed_items)
def __contains__(self, item):
return item in self._allowed
allowlist = AllowList(['admin', 'moderator', 'user'])
print('admin' in allowlist) # True
print('guest' in allowlist) # False
Sized and Hashable¶
from collections.abc import Sized, Hashable
# String is both Sized and Hashable
text = "hello"
print(isinstance(text, Sized)) # True
print(isinstance(text, Hashable)) # True
# List is Sized but not Hashable
lst = [1, 2, 3]
print(isinstance(lst, Sized)) # True
print(isinstance(lst, Hashable)) # False
Practical Example: LRU Cache Using ABC¶
from collections.abc import MutableMapping
class SimpleLRUCache(MutableMapping):
def __init__(self, max_size=10):
self._cache = {}
self._access_order = []
self.max_size = max_size
def __getitem__(self, key):
self._access_order.remove(key)
self._access_order.append(key)
return self._cache[key]
def __setitem__(self, key, value):
if len(self._cache) >= self.max_size and key not in self._cache:
oldest = self._access_order.pop(0)
del self._cache[oldest]
if key in self._cache:
self._access_order.remove(key)
self._cache[key] = value
self._access_order.append(key)
def __delitem__(self, key):
del self._cache[key]
self._access_order.remove(key)
def __iter__(self):
return iter(self._cache)
def __len__(self):
return len(self._cache)
cache = SimpleLRUCache(3)
cache['a'] = 1
cache['b'] = 2
cache['c'] = 3
cache['d'] = 4 # Evicts 'a'
print(dict(cache)) # {'b': 2, 'c': 3, 'd': 4}