I might have balked at some of this advice until a few days ago, when I tried to create an FHE-encrypted key/value store that could be used as a drop-in replacement for `dict`. As it turns out, subclassing `dict` is awkward — especially if you're actively trying to override __setitem__, or make the object serializable with `pickle` (the latter goal actually introduced me to a low-level dundermethod I hadn't come across before, and hope to never touch again: __reduce__, the evil stepfather of __getstate__ and __setstate__).
I really wanted these instances to be indistinguishable from ordinary `dict` objects as far as interface goes, so it seemed like an optimal use-case for inheritance. But in hindsight it seems like the "composition over inheritance" principle is ushering me to stash k,v pairs in a dictionary attribute of an ordinary (non-subclassed) class object and simply define methods such as update, delete, __setitem__, etc., rather than inheriting them. I don't think that's unreasonable, but the bigger problem I see with that approach is has to do with type dispatching: what if a user of this class is checking whether an object is an instance of `dict` (or `typing.Mapping` for that matter)?
> The UserDict class initializer makes a dictionary which it stores in self.data. All of the methods on this dictionary-like UserDict class wrap around this self.data dictionary.
Incredible. This appears to be exactly the solution to my problem. Thanks! (And, if thunner happens to come across this: thanks, from a former TA of yours!)
What? He lost me there. While that fellow clearly knows a lot more about OOP than me, statements like that, which are not exactly self-evident and go against prior best practices ("don't repeat thyself") need to be justified, otherwise it just looks like just some other random dude's opinion piece.
I thought that from context it was clear that it means “Code sharing _via subclassing_ is a bad idea.” which the whole previous section tried to establish. I have clarified the sentence.
I really wanted these instances to be indistinguishable from ordinary `dict` objects as far as interface goes, so it seemed like an optimal use-case for inheritance. But in hindsight it seems like the "composition over inheritance" principle is ushering me to stash k,v pairs in a dictionary attribute of an ordinary (non-subclassed) class object and simply define methods such as update, delete, __setitem__, etc., rather than inheriting them. I don't think that's unreasonable, but the bigger problem I see with that approach is has to do with type dispatching: what if a user of this class is checking whether an object is an instance of `dict` (or `typing.Mapping` for that matter)?