Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
328: collections.abc for Custom Container Types
A few years ago, I was reviewing a PR from a junior dev who had built a custom TimeSeries class. He'd spent a lot of time implementing __getitem__ and __len__ so the object felt like a list. Everything worked great in his unit tests, but the moment he passed that object into a third-party data visualization library, it crashed. The library was doing a check like if isinstance(data, Sequence): before processing. Even though his class "quacked" like a sequence, it wasn't officially one. He spent a whole afternoon manually adding dunder methods he didn't even want to write, just to satisfy the library's type checks.
That's where collections.abc comes in. While Python loves duck typing, there are times when you need a formal contract. Abstract Base Classes (ABCs) in the collections module let you explicitly declare that your custom container is a Sequence, a Mapping, or a Set. This doesn't just make isinstance checks work; it actually saves you from writing a lot of redundant code.
Bridging the Gap Between Duck Typing and Formal Contracts
In Python, we usually say, "if it has a __getitem__ method, it's probably a sequence." But relying solely on that can be fragile when you're integrating with larger ecosystems or building a framework for other developers. By inheriting from a class in collections.abc, you're telling Python—and other developers—exactly what your object is designed to do.
Take collections.abc.Sequence. If you inherit from it, you're committing to implementing __getitem__ and __len__. But here is the magic: the ABC provides "mixins." Because it knows that any sequence can be iterated over or checked for membership using in, the ABC provides default implementations of __iter__ and __contains__ for you. You get those features for free, based solely on the two methods you actually care about.
from collections.abc import Sequence
class MyReadOnlyList(Sequence):
def __init__(self, data):
self._data = data
def __getitem__(self, index):
return self._data[index]
def __len__(self):
return len(self._data)
# Even though we didn't define __contains__, it works because of the ABC!
my_list = MyReadOnlyList([10, 20, 30])
print(20 in my_list) # True
Reducing Boilerplate with Mapping and MutableSequence
The same logic applies to more complex containers. If you're building a custom cache or a configuration object, you'll likely want it to behave like a dictionary. Inheriting from collections.abc.Mapping forces you to implement __getitem__, __iter__, and __len__, but it gives you get(), keys(), values(), and items() for free. I can't tell you how many times I've seen developers manually write a keys() method that just returns self.__iter__—it's a waste of time when the ABC does it for you.
If your container is meant to be modified, you'll look toward the "Mutable" variants, like MutableSequence or MutableMapping. These require a few more methods (like __setitem__ and __delitem__), but in exchange, they provide the logic for append(), extend(), pop(), and update(). It turns your class from a simple data holder into a fully-fledged Python container without you having to reimplement the standard library's logic from scratch.
Just a heads-up: always remember that these are abstract base classes. If you inherit from Sequence but forget to implement __len__, Python will raise a TypeError the moment you try to instantiate your class. It's a safety feature—the language is effectively telling you, "You promised this would be a Sequence, but you forgot a requirement."
📋 Practical Task
Build a Read-Only Configuration Registry
You need to create a class called ConfigRegistry that behaves like a read-only dictionary. This is useful for application settings that should be accessible via key-lookup but should not be modified at runtime.
Requirements:
- Inherit from
collections.abc.Mapping. - The constructor
__init__should accept a dictionary of settings. - Implement the three required methods for
Mapping:__getitem__,__iter__, and__len__. - Verify that you can use the
.get()method and the.items()method, despite not implementing them yourself. - Ensure that attempting to use
isinstance(registry, collections.abc.Mapping)returnsTrue.
from collections.abc import Mapping
class ConfigRegistry(Mapping):
# Your code here
pass
# Test your implementation
settings = {"api_key": "12345", "timeout": 30, "debug": True}
registry = ConfigRegistry(settings)
print(registry["api_key"]) # Should print 12345
print(registry.get("timeout")) # Should print 30 (provided by ABC)
print(list(registry.keys())) # Should print ['api_key', 'timeout', 'debug'] (provided by ABC)
There are no comments for now.