Coding style 如何在一行代码中复制并修改dict

Coding style 如何在一行代码中复制并修改dict,coding-style,python,Coding Style,Python,我经常需要创建一个或两个不同于另一个的dict。以下是我通常做的: setup1 = {'param1': val1, 'param2': val2, 'param3': val3, 'param4': val4, 'paramN': valN} setup2 = copy.deepcopy(dict(setup1)) setup2.update({'param1': val10,

我经常需要创建一个或两个不同于另一个的dict。以下是我通常做的:

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

setup2 = copy.deepcopy(dict(setup1))
setup2.update({'param1': val10, 
                   'param2': val20})
程序中有一个点是
setup2
setup1
完全相同,这一点让我感到紧张,因为我担心在程序生命的某个时刻,这两行可能会分离,这是一个滑向太多bug的斜坡

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

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

解决方案 为此构建一个函数

当您在代码中使用它时,您的意图会更清楚,并且您可以在一个地方处理复杂的决策(例如,深度副本与浅层副本)

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'}
如果需要深度拷贝,请使用以下模块:

而不是:

result=dict(setup1)               # Shallow copy
确保字典中的所有对象都支持深度复制(任何可以复制的对象都应该支持)

这仅在更新字典的所有键都已包含在
setup1
中时有效

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

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

这样,如果新键在
setup1
中不存在,它们就会被添加,否则它们会替换旧的键/值对。

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

# setup1 is of Dict type (see below)
setup2 = setup1 + {'param1': val10}
你所要做的就是

  • 使用
    UserDict
    作为基类定义新类
  • 为其实现
    \uuuuuuuuuuuuuuuuuuuu
    方法

比如:


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

dict(a.items() + b.items())
如果“a”和“b”都有某个相同的键,则结果将具有来自b的值。
如果您使用的是Python 3,连接将不起作用,但您可以通过将生成器冻结到列表或使用itertools.chain函数来实现同样的效果。

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

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})

笔记
  • dict.copy()
  • 所有键都需要是字符串,因为它们是作为关键字参数传递的

这是亚当·马坦(Adam Matan)发布的漂亮答案的延伸:

def copy_dict(d,diff={},**kwargs):
res=dict(d)
资源更新(差异)
资源更新(kwargs)
返回res
唯一的区别是添加了kwargs。 现在人们可以写作了

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

setup2=copy\u dict(setup1,param1=val10,param2=val20)

我认为最简单的方法是这样的:

setup2 = dict(setup1).merge({'param1': val10, 
                        'param2': val20})
new_dict = {**old_dict, 'changed_val': value, **other_new_vals_as_dict}
我喜欢这一行(在itertools导入链的
之后):

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

(感谢juanpa.arrivillaga的改进!)

setup2=dict(setup1)
是浅拷贝,而不是深拷贝。
setup2=dict(setup1)
不是深拷贝。另外,还有一个叫做函数的东西,只要写一个。+1很好,尽管我更喜欢函数,因为1。Python2.6与dict理解不兼容;2.如果重复此操作,则单个复制点更符合单选原则。@亚当:这不是字典理解,因此在Python 2.6中工作正常。如果
setup1
中不存在
'param1'
键,则此操作不起作用,因此,它在setup2中也不会出现。@Adam:我刚刚注意到我的代码完全错了——现在更正:)第二种形式非常好而且干净,很棒!还不错:)您还可以直接使用对列表,而不是
{…}.items()
+1。还值得指出的是,通过使用
iteritems()
并将“+”替换为
itertools.chain(…)
这对于大型dict来说是非常有效的,如果您正在处理url变量以及更改一个变量的内容,那么将所有其他变量都绑定到特定的Python版本?在3.4中,这将返回一个
TypeError:+:“dict\u items”和“dict\u items”的不支持的操作数类型。
。是的,这是Python 21。这不允许添加两个
Dict
实例。使用
isinstance({dict,dict)
而不是
type({dict)==type({})
来解决这个问题(不管怎样,不建议使用后一种检查类型的方法,不仅仅是在这种情况下)。2. <代码>用户权限。用户权限仅因历史原因而存在。只需从
dict
派生即可。3.“总和”应该是一个
Dict
,而不是一个普通的
Dict
。4.通过
tmp=Dict(self)更容易创建“和”;tmp.update(_dict)
@Sven:感谢您的反馈。我是一个python新手:)我只是想证明这是可以做到的。无论如何,我会更新。
现在副本是原子的,假设没有线程参与
这是什么意思?作者的意思是“从代码的角度来看是原子的”(我假设他们的意思是,它只需要一行代码)。他们说这对线程不安全,但由于这是一个复制操作,线程不安全的唯一原因是当另一个线程试图复制它们时,另一个线程修改了
source\u dict
diff
。如果
source\u dict
diff
都没有修改,那么它也应该是线程安全的。当然,我可能会错过另一个线程不安全的来源:有人看到了吗?或者只是在调用
list
tuple
的过程中包装每个线程。这意味着你可以非常方便地执行
new=dict(old,**mods)
。从所有的答案来看,这就是我想要的!为什么不呢
dict(a.items() + b.items())
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})
new_dict = {**old_dict, 'changed_val': value, **other_new_vals_as_dict}