Python 字典深拷贝

21

我想知道在以下情况下深度复制是如何工作的:

from copy import deepcopy

def copyExample:
    self.myDict = {}
    firstPosition = "First"
    firstPositionContent = ["first", "primero"]
    secondPosition = "Second"
    secondPositionContent = ["second"]
    self.myDict[firstPosition] = firstPositionContent 
    self.myDict[secondPosition] = secondPositionContent
    return deepcopy(self.myDict)

def addExample(self):
    copy =  self.copyExample()
    copy["Second"].add("segundo")

它会返回我在字典中的那些列表的引用吗?还是像我期望的一样,将每个列表复制到一个具有不同引用的新列表中?

我知道深拷贝是什么(所以不需要解释深拷贝和浅拷贝之间的区别),但我想知道它是否按照我期望的方式工作,因此在使用addExample()时不更改实例变量。


1
你是否打印了这两个字典来查看它们是否不同?你看到了什么?它们是不同的吗?如果是这样的话,那说明复制的字典有一个新的列表,并且你向其中添加了一个元素。 - S.Lott
2个回答

16

文档很清楚地表明,您得到的是新副本而不是引用。Deepcopy为内置类型创建深层副本,但有各种例外情况,并且您可以为用户定义的对象添加自定义复制操作,以便为它们获得深层拷贝支持。如果您不确定,那就需要进行单元测试。


我认为它没有说明内置类型,它说明它会“复制”可选对象...这是否意味着我会得到一个新的列表引用? - mandel
8
Deepcopy有一系列特定的例外情况,除此之外所有的内容都会被复制。"这个模块不会复制像模块、方法、堆栈跟踪、堆栈帧、文件、套接字、窗口、数组或任何类似类型的东西。" 你将得到一个新的列表而不是对原列表的引用。打印你的示例中的两个字典并查看它们。 - S.Lott

3
我知道这不是回答您的问题,但我认为对于查看这个问题的人来说,这一点值得注意。
如果您要复制的数据本质上很简单,那么深度复制可能会过度。我所说的简单是指如果您的数据可以表示为Json。让我用代码来说明:
我使用http://www.json-generator.com/获取了一些示例json数据。
def deepCopyList(inp):
    for vl in inp:
        if isinstance(vl, list):
            yield list(deepCopyList(vl))
        elif isinstance(vl, dict):
            yield deepCopyDict(vl)
        else:
            yield vl

            
def deepCopyDict(inp):
    outp = inp.copy()
    for ky, vl in outp.iteritems():
        if isinstance(vl, dict):
            outp[ky] = deepCopyDict(vl)      
        elif isinstance(vl, list):
            outp[ky] = list(deepCopyList(vl))  
    return outp
    
def simpleDeepCopy(inp):
    if isinstance(inp, dict):
        return deepCopyDict(inp)
    elif isinstance(inp, list):
        return deepCopyList(inp)
    else:
        return inp

if __name__ == '__main__':
    import simplejson as json
    import time
    from copy import deepcopy
    fl = open('sample.json', 'r')
    sample = json.load(fl)
    start = time.time()
    for _ in xrange(10000):
        tmp = simpleDeepCopy(sample)
    end = time.time()
    print 'simpleDeepCopy: ' + str(end - start)
    start = time.time()
    for _ in xrange(10000):
        tmp = deepcopy(sample)
    end = time.time()
    print 'copy.deepcopy: ' + str(end - start)

输出:

simpleDeepCopy: 0.0132050514221
copy.deepcopy: 2.66142916679

simpleDeepCopy: 0.0128579139709
copy.deepcopy: 2.60736298561

“简单的意思是,如果您的数据可以表示为Json” - 这是错误的陈述:即使一些简单的“可JSON化”对象也可能需要.deepcopy()来避免引用。尝试这个:a = {1:'A', 2:['a', 'b', 'c'], 3:'Z'}; b = a.copy(); a[2].append('d'); print b - MestreLion
3
如果数据可以表示为JSON,为什么不直接使用json.loads(json.dumps(data))呢? - rob

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