
On Fri, Oct 12, 2018 at 02:45:30AM +1100, Chris Angelico wrote:
On Fri, Oct 12, 2018 at 2:41 AM Chris Barker - NOAA Federal via Python-ideas <python-ideas@python.org> wrote:
This violates the Liskov Substitution Principle.
If we REALLY had a time machine, then dict would subclass frozendict, and we’d be all set.
Thanks to virtual subclassing, we can still do this. The question is, should we?
Intuition tells me that a frozen dictionary is a form of dictionary that adds restrictions, not that a dictionary is a frozen dictionary that you left out to thaw.
No offence Chris, but that's why we shouldn't program by intuition :-) We don't build Smart cars by starting with a Hummer and slicing off the bits that aren't needed. We already have prior art demonstrating best practice in the form of the Mapping and MutableMapping ABCs, and frozenset versus set for concrete classes. Best practice is not to subclass a type and restrict existing functionality, but to start with a restricted class and extend functionality. Or not to subclass at all. Subclassing is not the only way to DRY -- there are other ways for frozendict and dict to share code other than subclassing, although they're not necessarily efficient or easy if frozendict is written in pure Python. One way is delegation to a hidden dict (like the MappingProxyType, except we ensure the dict is private and not shared). # Just a sketch, not a full implementation. class frozendict(object): def __new__(cls, *args, **kwargs): instance = super().__new__(cls) instance.__d = dict(*args, **kwargs) return instance # Define only the methods we want, delegating to the # hidden dict. def __getitem__(self, key): return self.__d[key] def keys(self): return self.__d.keys() def items(self): return self.__d.items() The trickiest part is probably getting hashing right. I think this would work: def __hash__(self): return hash(tuple(self.items()))
But as we see from [frozen]set, it's probably best to treat them as completely independent classes, both implementing the basic Mapping interface.
Indeed. -- Steve