如何复制一个字典并在一行代码中修改它

时间:2011-04-05 12:19:24

标签: coding-style python

我经常需要创建一个或两个项目彼此不同的词汇。这是我通常做的事情:

setup1 = {'param1': val1, 
            'param2': val2,
            'param3': val3,
            'param4': val4,
            'paramN': valN}

setup2 = copy.deepcopy(dict(setup1))
setup2.update({'param1': val10, 
                   'param2': val20})

程序中有一点setup2setup1的相同副本的事实让我感到紧张,因为我害怕在程序生命的某些时刻这两行可能会分开,这是一个滑向太多错误的斜坡。

理想情况下,我希望能够在一行代码中完成此操作(如下所示):

setup2 = dict(setup1).merge({'param1': val10, 
                        'param2': val20})

当然,我可以使用分号将两个命令压缩到一个物理行中,但这对我来说非常难看。还有其他选择吗?

9 个答案:

答案 0 :(得分:38)

我认为最简单的方法是:

new_dict = {**old_dict, 'changed_val': value, **other_new_vals_as_dict}

答案 1 :(得分:21)

setup2 = dict(setup1.items() + {'param1': val10, 'param2': val20}.items())

这样,如果setup1中不存在新密钥,则会添加新密钥,否则会替换旧密钥/值对。

答案 2 :(得分:18)

您可以在字典构造函数中使用关键字参数进行更新

new = dict(old, a=1, b=2, c=3)

# You can also unpack your modifications
new = dict(old, **mods)

这相当于:

new = old.copy()
new.update({"a": 1, "b": 2, "c": 3})

Source

注意:dict.copy()会创建副本。

答案 3 :(得分:15)

解决方案

为此构建一个函数。

当您在代码中使用它时,您的意图会更清晰,并且您可以在一个地方处理复杂的决策(例如,深拷贝和浅拷贝)。

def copy_dict(source_dict, diffs):
    """Returns a copy of source_dict, updated with the new key-value
       pairs in diffs."""
    result=dict(source_dict) # Shallow copy, see addendum below
    result.update(diffs)
    return result

现在副本是原子的,假设没有涉及线程:

setup2=copy_dict(setup1, {'param1': val10, 'param2': val20})

附录 - 深层复制

对于基元(整数和字符串),不需要深层复制:

>>> d1={1:'s', 2:'g', 3:'c'}
>>> d2=dict(d1)
>>> d1[1]='a'
>>> d1
{1: 'a', 2: 'g', 3: 'c'}
>>> d2
{1: 's', 2: 'g', 3: 'c'}

如果您需要深层副本,请使用copy模块:

result=copy.deepcopy(source_dict) # Deep copy

而不是:

result=dict(setup1)               # Shallow copy

确保字典中的所有对象都支持深层复制(任何可以pickled可以做的对象)。

答案 4 :(得分:13)

setup2 = dict((k, {'param1': val10, 'param2': val20}.get(k, v))
              for k, v in setup1.iteritems())

仅当更新词典的所有键都已包含在setup1中时才有效。

如果您的所有键都是字符串,您也可以

setup2 = dict(setup1, param1=val10, param2=val20)

答案 5 :(得分:2)

如果您只需要使用多个词典中的项目创建新词典,则可以使用:

dict(a.items() + b.items())

如果“a”和“b”都有一些相同的键,则结果将具有b的值。 如果您使用的是Python 3,则连接将不起作用,但您可以通过将生成器冻结到列表或使用itertools.chain函数来执行相同的操作。

答案 6 :(得分:0)

您可以使用UserDict包装器编写自己的类,只需添加dict类似

# setup1 is of Dict type (see below)
setup2 = setup1 + {'param1': val10}

你所要做的就是

  • 使用UserDict作为基类
  • 定义新类
  • 为其实施__add__方法。

类似于:

class Dict(dict):
    def __add__(self, _dict):
        if isinstance(_dict, dict):
            tmpdict = Dict(self)
            tmpdict.update(_dict)
            return tmpdict

        else:
            raise TypeError

    def __radd__(self, _dict):
         return Dict.__add__(self, _dict)

答案 7 :(得分:0)

这是Adam Matan发布的好答案的扩展:

def copy_dict(d, diffs={}, **kwargs):
    res = dict(d)
    res.update(diffs)
    res.update(kwargs)
    return res

唯一的区别是增加了kwargs。 现在可以写

setup2 = copy_dict(setup1, {'param1': val10, 'param2': val20})

setup2 = copy_dict(setup1, param1=val10, param2=val20)

答案 8 :(得分:0)

我喜欢这一行(在from itertools import chain之后):

d3 = dict(chain(d1.items(), d2.items()))

(感谢juanpa.arrivillaga的改进!)