class OrderedDefaultDict, __missing__(), kwargs.pop('default_factory')

- Src: https://gist.github.com/westurner/be22dba8110be099a35e#file-ordereddefaultdict-py

From https://groups.google.com/d/msg/python-ideas/9bpR8-bNC6o/tQ92g7wLGAAJ :

On Fri, Oct 16, 2015 at 9:08 PM, Andrew Barnert via Python-ideas 
<python-ideas@python.org> wrote:
Actually, forget all that; it's even simpler.

At least in recent 3.x, the only thing wrong with inheriting from both types, assuming you put OrderedDict first, is the __init__ signature. So:

    class OrderedDefaultDict(OrderedDict, defaultdict):
        def __init__(self, default_factory=None, *a, **kw):
            OrderedDict.__init__(self, *a, **kw)
            self.default_factory = default_factory

More importantly, because __missing__ support is built into dict, despite the confusing docs for defaultdict, you don't really need defaultdict at all here:

    class OrderedDefaultDict(OrderedDict):
        def __init__(self, default_factory=None, *a, **kw):
            OrderedDict.__init__(self, *a, **kw)
            self.default_factory = default_factory
        def __missing__(self, key):
            self[key] = value = default_factory()
            return value

And either of these should work with 2.5+ (according to https://docs.python.org/2/library/stdtypes.html#dict that's when dict.__missing__ was added).

...

This seems to keep a consistent __init__ signature with OrderedDict (by .pop()-ing 'default_factory' from kwargs instead of specifying as a positionalkwarg):
 

class OrderedDefaultDict(OrderedDict):
    def __init__(self, *a, **kw):
        default_factory = kw.pop('default_factory', self.__class__)
        OrderedDict.__init__(self, *a, **kw)
        self.default_factory = default_factory
    def __missing__(self, key):
        self[key] = value = self.default_factory()
        return value
 

I've added a few tests (as well as to_json, and _repr_json_
https://gist.github.com/westurner/be22dba8110be099a35e/c1a3a7394e401d4742df0617900bde6ab2643300#file-ordereddefaultdict-py-L120-L122
(Without this fix, 
json.loads(output_json, object_pairs_hook=OrderedDefaultDict)
doesn't seem to work). 

On Thu, Mar 9, 2017 at 4:57 PM, Chris Barker <chris.barker@noaa.gov> wrote:


>If we really want to make defaultdict feel more "builtin" (and I don't see
>any reason to do so), I'd suggest adding a factory function:
>
>dict.defaultdict(int)
 
Nice.

I agree -- what about:

dict.sorteddict() ??

make easy access to various built-in dict variations...

-CHB


--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R            (206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115       (206) 526-6317   main reception

Chris.Barker@noaa.gov

_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/