【问题标题】:Python dictionary deepcopyPython字典深拷贝
【发布时间】:2010-10-24 17:31:22
【问题描述】:

我想知道 deepcopy 在以下情况下究竟是如何工作的:

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

它是否返回对我在字典中的列表的引用?或者它是否按我的预期工作并将每个列表复制到具有不同引用的新列表中?

我知道什么是深拷贝(所以没有必要解释深拷贝和浅拷贝之间的区别),但我想知道它是否像我期望的那样工作,因此当我使用 @ 时不要更改实例变量987654322@.

【问题讨论】:

  • 您是否打印了这两个字典以查看它们是否不同?你看见什么了?他们有什么不同吗?如果是这样,则副本有一个新列表,您在其中添加了一个元素。

标签: python dictionary deep-copy


【解决方案1】:

我知道这并没有回答你的问题,但我认为这对于关注这个问题的人来说是值得注意的。

如果您要复制的数据本质上很简单,那么 deepcopy 可能会有点矫枉过正。本质上很简单,我的意思是您的数据是否可以表示为 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)

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-able”对象也可能需要 .deepcopy() 以避免引用。试试这个:a = {1:'A', 2:['a', 'b', 'c'], 3:'Z'}; b = a.copy(); a[2].append('d'); print b
  • 如果数据可以表示为 JSON,为什么不直接使用json.loads(json.dumps(data))..?
【解决方案2】:

documentation 清楚地表明您获得的是新副本,而不是参考。 Deepcopy 为内置类型创建深层副本,但有各种例外情况,您可以向用户定义的对象添加自定义复制操作,以获得对它们的深层复制支持。如果您不确定,那么这就是单元测试的用途。

【讨论】:

  • 我不认为它声明了内置类型,它声明它确实“复制”了可挑选的对象......这是否意味着我会得到一个新的列表引用?
  • Deepcopy 有一个简短的例外列表。其他一切都被复制。 “此模块不会复制模块、方法、堆栈跟踪、堆栈帧、文件、套接字、窗口、数组或任何类似类型等类型。”你会得到一个新的列表。不是对列表的引用,而是新列表。打印示例中的两个字典并查看它们。
猜你喜欢
  • 1970-01-01
  • 2015-01-13
  • 2020-11-06
  • 2015-07-31
  • 2017-10-14
  • 2012-04-12
  • 2020-04-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多