collections.abc .register() Makes isinstance Pass But Grants No Methods (tested)
Properly subclassing collections.abc.Mapping gets you two things at once: isinstance()/issubclass() recognize your class as a Mapping, and you inherit real, working mixin methods like get(), keys(), items(), values(), and __contains__() for free, built on top of the three abstract methods (__getitem__, __len__, __iter__) you're required to implement. Calling Mapping.register(YourClass) instead -- the documented way to make an unrelated class satisfy isinstance checks without inheriting from the ABC -- only does the first half. It never touches your class's code at all, so none of the mixin methods exist, even if you also happen to implement the three abstract methods yourself.
1. register() makes isinstance pass with zero implementation
from collections.abc import Mapping
class FakeMapping:
pass
Mapping.register(FakeMapping)
f = FakeMapping()
print("isinstance:", isinstance(f, Mapping))
try:
f.get("x")
except AttributeError as e:
print("f.get() ->", e)
try:
len(f)
except TypeError as e:
print("len(f) ->", e)
isinstance: True
f.get() -> 'FakeMapping' object has no attribute 'get'
len(f) -> object of type 'FakeMapping' has no len()
Measured: isinstance(f, Mapping) is True -- any code that branches on isinstance(x, Mapping) will treat f as a mapping. But f has none of Mapping's abstract methods, let alone its mixins; calling anything on it fails immediately. register() is purely a registration for isinstance/issubclass -- it does not touch the class's attributes, bases, or MRO at all.
2. Real subclassing gives you the mixin methods for free
from collections.abc import Mapping
class RealMapping(Mapping):
def __init__(self, d):
self._d = d
def __getitem__(self, k):
return self._d[k]
def __len__(self):
return len(self._d)
def __iter__(self):
return iter(self._d)
r = RealMapping({"a": 1})
print(r.get("a"), r.get("z", "default"))
print(list(r.keys()))
print(isinstance(r, Mapping))
1 default
['a']
True
Measured: implementing just the three required abstract methods via real subclassing gives working get(), keys(), and every other Mapping mixin method automatically -- Mapping's source defines them in terms of the three abstract methods, and they're inherited normally through the class hierarchy that register() never creates.
3. Even implementing the abstract methods yourself doesn't help after register()
from collections.abc import Mapping
class ManualMapping:
def __init__(self, d):
self._d = d
def __getitem__(self, k):
return self._d[k]
def __len__(self):
return len(self._d)
def __iter__(self):
return iter(self._d)
Mapping.register(ManualMapping)
m = ManualMapping({"a": 1})
print(isinstance(m, Mapping))
try:
m.get("a")
except AttributeError as e:
print("m.get() ->", e)
True
m.get() -> 'ManualMapping' object has no attribute 'get'
Measured: implementing the three abstract methods by hand and then registering instead of subclassing still leaves get() missing. The mixin methods only exist as code defined on the Mapping class itself; without inheriting from it, nothing provides them, no matter how faithfully the abstract methods are reimplemented.
Frequently asked questions
Does collections.abc.Mapping.register() give my class the .get()/.keys() methods?
No. We measured that register() only affects isinstance()/issubclass() checks -- it never touches the registered class's attributes or bases, so none of Mapping's mixin methods (get, keys, items, values, __contains__) become available, even if the class separately implements all three required abstract methods.
How do I get the free mixin methods from an ABC like Mapping?
Subclass it directly (class Foo(Mapping): ...) and implement the required abstract methods (__getitem__, __len__, __iter__ for Mapping) -- we measured this giving working get()/keys()/items()/values() automatically, inherited from Mapping's own code.
Why does register() exist if it doesn't grant any methods?
It's meant for making an already-complete, independently-implemented class (often one you don't control, like a C extension type) satisfy isinstance checks for duck-typing purposes, without altering its class hierarchy. It assumes the class already behaves like a Mapping on its own; it doesn't grant any behavior.
Does this affect other collections.abc classes besides Mapping?
Yes -- the same register()-vs-subclass distinction applies to every ABC in collections.abc (Sequence, Set, Iterable, Callable, etc.): register() only ever affects isinstance/issubclass, never grants mixin methods or enforces the abstract methods actually being implemented.
Written with AI assistance. Measured on 2026-10-08 with Python 3.13.5's built-in collections.abc.Mapping: registered a plain class with Mapping.register() (implementing none of Mapping's abstract methods), then compared isinstance() results and available methods against a second class that properly subclasses Mapping and implements its three required abstract methods. PlainHeaders is our extension; Python's collections.abc module is built in.