NestedDefaultOrderedDict on Python

python 3.7 부터는 dict 의 order 가 보장되지만, 낮은 버전의 python 에서는 order 이 보장되지 않을 수 있습니다. (3.5 에서는 order 가 보장되지 않음. OrderedDict 를 사용해야 함.)

그리고, 다음과 같이 nested dict 를 초기화 하기위해서는 nested = lambda: collections.defaultdict(nested) 와 같은 선언 해야 했습니다.

# a = []
a = nested()
a['a']['b'] = 'c'

nested dict 같은 초기화도 되면서, OrderedDict 처럼 order 보장이 되는 dict 구현체는 없나? 같은 필요가 생기면서 찾다보니 stackoverflow 답변중 구현체가 있어서 기록겸 내용을 남겨둡니다.

from collections import OrderedDict, Callable

class DefaultOrderedDict(OrderedDict):
    # Source: http://stackoverflow.com/a/6190500/562769
    def __init__(self, default_factory=None, *a, **kw):
        if (default_factory is not None and
           not isinstance(default_factory, Callable)):
            raise TypeError('first argument must be callable')
        OrderedDict.__init__(self, *a, **kw)
        self.default_factory = default_factory

    def __getitem__(self, key):
        try:
            return OrderedDict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)

    def __missing__(self, key):
        if self.default_factory is None:
            raise KeyError(key)
        self[key] = value = self.default_factory()
        return value

    def __reduce__(self):
        if self.default_factory is None:
            args = tuple()
        else:
            args = self.default_factory,
        return type(self), args, None, None, self.items()

    def copy(self):
        return self.__copy__()

    def __copy__(self):
        return type(self)(self.default_factory, self)

    def __deepcopy__(self, memo):
        import copy
        return type(self)(self.default_factory,
                          copy.deepcopy(self.items()))

    def __repr__(self):
        return 'OrderedDefaultDict(%s, %s)' % (self.default_factory,
                                               OrderedDict.__repr__(self))

def NestedDict():
    return DefaultOrderedDict(NestedDict)

사용법은 생각했던 대로, 다음과 같이 쓰면 됩니다.

a = NestedDict()
a['a']['b'] = 'c'

참..쉽죠@.@?


comments powered by Disqus