2

这是与此处提供的解决方案相关的问题,它涉及以下代码作为解决方案:

from collections import MutableMapping

def set_value(d, keys, newkey, newvalue, default_factory=dict):
    """
    Equivalent to `reduce(dict.get, keys, d)[newkey] = newvalue`
    if all `keys` exists and corresponding values are of correct type
    """
    for key in keys:
        try:
            val = d[key]
        except KeyError:
            val = d[key] = default_factory()
        else:
            if not isinstance(val, MutableMapping):
                val = d[key] = default_factory()
        d = val
    d[newkey] = newvalue

我希望有人能给我一些解释为什么这段代码有效。我很困惑传入的 dict 'd' 不会在 d = val 的地方不断被覆盖。dict 'd' 如何在不索引到下一个节点的情况下继续获得更多嵌套字典?抱歉,如果这没有意义,我不明白这是如何工作的。

谢谢你的帮助!

4

2 回答 2

2

d反弹;变量被更新为指向val每个循环。

对于每个keyin keys,要么找到键(val = d[key]成功) ,要么使用 为该键default_factory()创建新值。

如果找到键但值不是MutableMapping类型,则将找到的值替换为新default_factory()结果。

一旦确定了这个级别的新值,d就会被告知忘记旧字典并指向新字典。

重新绑定不会更改旧值。它只是停止引用那个旧值。

让我们用一个简单的例子:

>>> d = {'foo': {}}
>>> keys = ['foo']
>>> newkey = 'bar'
>>> newval = 'eggs'
>>> original = d

一开始,originald都是同一个对象。将此处的名称视为纸质标签,将其值视为气球。标签用绳子系在气球上。在上面的示例中,doriginal标签绑定到同一个字典气球。

当我们进入for key in keys循环时,d[key]查找成功并与空字典val的结果相关联:d['foo']

>>> key = keys[0]
>>> key
'foo'
>>> val = d[key]
>>> val
{}

这是一个普通的 Python 字典,并且isinstance(val, MutableMapping)True. 下一行将标签重新绑定到d该字典。该字符串只是从原始字典中解开,现在附加到同一个气球val上:

>>> d = val
>>> d
{}
>>> original
{'foo': {}}
>>> d is val
True
>>> d is original
False

重新装订并没有改变原来的字典!

用完键(只有一个keys),下一部分然后分配newvald[newkey]

>>> d[newkey] = newval
>>> d
{'bar': 'eggs'}

但是,d这不是附加到此词典气球的唯一标签。字典本身包含键和值,它们都是与气球相关的标签!original标签仍然绑定到外部字典气球,并且它有一个键foo关联值,它绑定到一个嵌套字典,而我们刚刚更改的就是这个嵌套字典:

>>> original
{'foo': {'bar': 'eggs'}}

该算法只是通过字符串跟随标签到新字典。

使用更复杂的组合键只意味着要遵循更多的字符串,可能还会增加一个额外的字典来绑定。

于 2013-09-08T23:24:14.800 回答
1

我认为你的问题归结为:

为什么d[newkey] = newvalue修改对象,而对对象d = var不做任何事情?

只是在 Python 中,您可以在函数中修改可变对象,但无法更改外部名称所指的对象。

于 2013-09-09T00:07:58.577 回答