有没有一种方法可以使用另一个字典在Python字典上设置多个默认值?

10
假设我在Python中有两个字典:
mydict = { 'a': 0 }

defaults = {
    'a': 5,
    'b': 10,
    'c': 15
}

我希望能够使用默认值从defaults中扩展mydict,使得'a'保持不变,但'b'和'c'被填充。我知道dict.setdefault()dict.update(),但每个都只完成了我想要的一半 - 使用dict.setdefault()时,我必须遍历defaults中的每个变量; 但是通过dict.update()defaults将覆盖mydict中任何预先存在的值。

Python中是否有我没有发现的功能可以实现这一点? 如果没有,那么编写循环以重复调用dict.setdefaults()是否有更Pythonic的方法,而不是像下面这样:

for key in defaults.keys():
    mydict.setdefault(key, defaults[key])

上下文:我正在使用Python编写一些控制如何解析XML树的数据。每个节点都有一个字典(即如何处理每个节点),我希望我编写的数据是稀疏的,但填充了默认值。示例代码只是一个示例...真正的代码在默认字典中有更多的键/值对。
(我意识到这整个问题只是一个小问题,但它一直困扰着我,所以我想知道是否有更好的方法来做到这一点,我不知道。)
6个回答

12

你不能让mydict成为default的复制品吗?这样,mydict将具备所有正确的初始值。

mydict = default.copy()

我考虑过这个问题,但是复制整个默认值是否会非常低效(尤其是如果mydict已经设置了所有的值)?在这种情况下,你将创建一个新的字典,将所有的值从另一个字典中复制出来,然后再重新写入整个字典。 - Dan Lew
2
@Daniel Lew:值不会被复制,只会有对它们的引用。新字典将在内存中有对相同值的新引用。 - nosklo
你可以测试一下速度 - 这肯定是更少的代码和更优雅,因为它立即清楚你想要做什么。我认为,它可能比你的方法更快,如果没有其他原因,那就是所有的操作都发生在解释器内部,并且很可能被相当优化了。 - Shane C. Mason

6
如果您不介意在过程中创建一个新的字典,这个方法可以解决问题:
newdict = dict(defaults)
newdict.update(mydict)

现在newdict包含你需要的内容。

6

自Python 3.9起,您可以这样做:

mydict = defaults | mydict

我在我的使用情境中发现这个解决方案最优雅。

5
您可以像Python的collections.DefaultDict一样完成这个操作:
class MultiDefaultDict(dict):
    def __init__(self, defaults, **kwargs):
        self.defaults = defaults
        self.update(kwargs)
    def __missing__(self, key):
        return self.defaults[key]

>>> mydict2 = MultiDefaultDict(defaults, a=0)
>>> mydict2['a']
0
>>> mydict2['b']
10
>>> mydict2
{'a': 0}

到目前为止,其他解决方法都会复制所有默认值;但是这个解决方法按要求共享它们。您可能想要覆盖其他字典方法(如__contains__()__iter__()items()keys()values()),但是此类在此处的定义中仅迭代非默认项。请注意保留HTML标记。

值得强调的是,与defaultdict(和setdefault())不同,任何缺失的键和相关的默认值实际上都没有被添加到底层字典中——这可能是需要的,也可能不是。在任何情况下,当然可以进行更改... - martineau

0
defaults.update(mydict)

那么我如何将我的默认设置应用到另一个节点呢? - Dan Lew
请在某处保留原始副本。 - SilentGhost
默认值是原始的。 :P - Dan Lew
更新后就不会了。你最好把这个新信息加到问题里。 - SilentGhost

0

个人喜欢附加字典对象。它的工作方式大多像一个字典,除了你必须先创建这个对象。

class d_dict(dict):
    'Dictionary object with easy defaults.'
    def __init__(self,defaults={}):
        self.setdefault(defaults)           
    def setdefault(self,defaults):
        for key, value in defaults.iteritems():
            if not key in self:
                dict.__setitem__(self,key,value)

这提供了与字典类型完全相同的功能,除了它覆盖了setdefault()方法并且可以接受包含一个或多个项的字典。您可以在创建时设置默认值。

这只是个人偏好。据我所知,dict.setdefault()所做的就是设置尚未设置的项。因此,可能最简单的选项是:

new_dict = default_dict.copy()
new_dict.update({'a':0})

然而,如果你这样做超过一次,你可能需要把它封装成一个函数。此时使用自定义字典对象可能更容易,而不是不断向你的字典添加默认值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接