pythondictionarydata-structuresautovivification

One line tree implementation


Based of this answer, I want to create a one line tree as part of another class like thus:

self._tree = collections.defaultdict(lambda: self._tree)

I will need to allow the users of said class to add path elements to the tree and run some callback starting at the lowest tree level. My naive implementation raises a error when I run pytest:

def _add(self, tree, path):
    for node in path:
        tree = tree[node]

def _run(self, tree, callback):
    for key in tree.keys():
        callback(tree[key]) # !!! Recursion detected (same locals & position)
        self._run(key)

This code works iff the tree is defined as

    def tree():
        return collections.defaultdict(tree)

    self._tree = tree()

Why is my naive approach not working with the lambda expression?


⚠ The Zen of Python states that

Simple is better than complex.

The one-line lambda makes the code complex where there is a simpler implementation. Therefore the one-line lambda should not be used in production code. However, I shall leave this question here for academic interest.


Solution

  • The one-line defaultdict design in the first linked question doesn't look right to me. It produces unusual self-referential loops:

    >>> d = collections.defaultdict(lambda: d)
    >>> d["a"] = 23
    >>> d["b"]["c"] = 42
    >>> print d["b"]["a"] #we never created a value with these keys, so it should just return a defaultdict instance.
    23
    >>> #uh, that's not right...
    

    A one-line lambda implementation of the function in your second link would look more like:

    tree = lambda: defaultdict(tree); self._tree = tree()


    Edit: looks like you can do it in a single statement with:

    self._tree = (lambda f: f(f))(lambda t: defaultdict(lambda: t(t)))
    

    ... But requiring college-level lambda calculus skills just to shrink your script by one statement seems like an unwise bargain. Consider a more understandable approach.