1

I needed to flatten a dictionary today. Meaning I wanted:

{'_id': 0, 'sub': {'a': 1, 'b':2}}

to become:

{'_id': 0, 'a':1, 'b':2}

So I thought I could be clever and pull off the following one-liner.

One-liner:

x = dict(_id=0, sub=dict(a=1, b=2))
y = x.pop('sub').update(x)  # incorrect result

This results in y = None.

So I obviously resorted to:

Multi-Step:

x = dict(_id=0, sub=dict(a=1, b=2))
y = x.pop('sub')
y.update(x)   # correct result

Setting "good expressive coding practices" asside for a moment, I would like to understand why the One-liner approach above yields None. I would have thought that x.pop('sub') would have resulted in a temporary dict on a stack somewhere and the original x dict would be immediately updated. Then the stack object would receive the next method in the chain which is the update. This obviously does not seem to be the case.

For the communities better understanding (and clearly mine) - how does python resolve the one-liner and result in None?

4

3 回答 3

10

.update()方法返回None,因为它就地更改了受影响的字典。.pop()确实返回弹出的值,即嵌套字典。

您正在更新包含的dict,为什么不更新 dict级呢?

x.update(x.pop('sub'))

结果:

>>> x = dict(_id=0, sub=dict(a=1, b=2))
>>> x.update(x.pop('sub'))
>>> x
{'a': 1, '_id': 0, 'b': 2}

或者您可以递归地执行此操作:

def inplace_flatten(d):
    keys = list(d.keys())
    for k in keys:
        if isinstance(d[k], dict):
            inplace_flatten(d[k])
            d.update(d.pop(k))
于 2012-11-26T18:28:20.333 回答
2

因为y得到 的结果dict.update(),即None

于 2012-11-26T18:28:44.240 回答
1

这应该可以解决问题

def flatten(d, answer=None):
    if answer == None:
        answer = {}
    if not d:
        return answer
    else:
        for k in d:
            if isinstance(d[k], dict):
                flatten(d[k], answer)
            else:
                answer[k] = d[k]
        return answer
于 2012-11-26T18:28:38.500 回答