• 我的Python学习笔记(二):浅拷贝和深拷贝


    在Python中,对象赋值,拷贝(浅拷贝和深拷贝)之间是有差异的,我们通过下列代码来介绍其区别

    一、对象赋值

    对象赋值不会复制对象,它只会复制一个对象引用,不会开辟新的内存空间

    如下例所示,将test赋值给copytest后,test和copytest的id值相同,test和copytest指向的是同一个list,所以当test的值改变时,copytest的值也相应改变

    test = ["test", 18, ["python","java"]]
    copytest = test
    print(test)         # ['test', 18, ['python', 'java']]
    print(copytest)     # ['test', 18, ['python', 'java']]
    print(id(test))     # 4559314816
    print(id(copytest)) # 4559314816
    
    test[0] = "changetest"
    test[2].append("css")
    print(test)         # ['changetest', 18, ['python', 'java', 'css']]
    print(copytest)     # ['changetest', 18, ['python', 'java', 'css']]
    print(id(test))     # 4559314816
    print(id(copytest)) # 4559314816

    二、拷贝

    对于复合对象,如果有时我们不想因为其中一个对象改变而改变另外一个对象的值,我们可以使用Python的copy模块。

    copy模块中包含如下两个方法:

     

    copy.copy(x)方法返回x的浅拷贝,copy.deepcopy(x)方法返回x的深拷贝

    我们来理解下浅拷贝和深拷贝的区别:

    浅拷贝和深拷贝的区别只与复合对象有关系(复合对象就是对象中包含其他对象,例如list和其他实例类)

    • 浅拷贝构造了一个新的复合对象,然后(尽可能)把原来的对象引用直接插入到新对象中
    • 深拷贝构造了一个新的复合对象,然后递归的将原对象中的内容进行复制,并插入新对象

      1、浅拷贝

    在下例中,浅拷贝会为copytest开辟新的内存空间,但copytest中的对象仍然是test中的对象引用,不会对其中的对象进行复制

    import copy
    
    test = ["test", 18, ["python","java"]]
    copytest = copy.copy(test)
    print(test)                     # ['test', 18, ['python', 'java']]
    print(copytest)                 # ['test', 18, ['python', 'java']]
    print(id(test))                 # 4484571008
    print(id(copytest))             # 4484611320
    print [id(x) for x in test]     # [4484554208, 140582137648080, 4484569424]
    print [id(x) for x in copytest] # [4484554208, 140582137648080, 4484569424]
    
    test[0] = "changetest"
    test[2].append("css")
    print(test)                     # ['changetest', 18, ['python', 'java', 'css']]
    print(copytest)                 # ['test', 18, ['python', 'java', 'css']]
    print(id(test))                 # 4484571008
    print(id(copytest))             # 4484611320
    print [id(x) for x in test]     # [4484554352, 140582137648080, 4484569424]
    print [id(x) for x in copytest] # [4484554208, 140582137648080, 4484569424]
    • test和copytest的id值不同,但copytest并没有将copy内的值重新拷贝一份,而是直接指向copy内的值。
    • 当执行test[0] = "changetest”时,test[0]重新指向字符串”changetest”,而copttest[0]仍然指向字符串”test”。
    • 当执行test[2].append("css”)时,更改了test[2]指向的list中的值,而test和copytest都指向此list,所以copytest也相应改变了

     注:字典的浅拷贝可以使用dict.copy(),list的浅拷贝可以使用slice截取整个list,例如:copied_list original_list[:]

      2、深拷贝:

    在下例中,深拷贝会为copytest开辟新的内存空间,并将test中的复合对象进行拷贝,并将其引用赋值给新copytest

    import copy
    
    test = ["test", 18, ["python","java"]]
    copytest = copy.deepcopy(test)
    print(test)                     # ['test', 18, ['python', 'java']]
    print(copytest)                 # ['test', 18, ['python', 'java']]
    print(id(test))                 # 4476972928
    print(id(copytest))             # 4477013240
    print [id(x) for x in test]     # [4476956224, 140706592084752, 4476971344]
    print [id(x) for x in copytest] # [4476956224, 140706592084752, 4477013312]
    
    test[0] = "changetest"
    test[2].append("css")
    print(test)                     # ['changetest', 18, ['python', 'java', 'css']]
    print(copytest)                 # ['test', 18, ['python', 'java']]
    print(id(test))                 # 4476972928
    print(id(copytest))             # 4477013240
    print [id(x) for x in test]     # [4476956512, 140706592084752, 4476971344]
    print [id(x) for x in copytest] # [4476956224, 140706592084752, 4477013312]
    • test和copytest的id值不同,copytest将test中的list重新拷贝了一份,并指向重新拷贝的list
    • 当执行test[0] = "changetest”时,test[0]重新指向字符串”changetest”,而copttest[0]仍然指向字符串”test”。
    • 当执行test[2].append("css”)时,更改了test[2]指向的list的值,但copytest和test指向的并不是同一个list,所以copytest并不受影响

    注:深拷贝存在两个问题:一个是递归拷贝可能导致递归循环,另一个是深拷贝会拷贝所有的对象,而有些可以复用的对象也会被重复拷贝,导致拷贝过多的情况

  • 相关阅读:
    getContentResolver()内容解析者查询联系人、插入联系人
    ContentProvider备份短信,以xml文件存储
    ContentProvider详解
    bindService初步了解
    Service之来电监听(失败的案例)
    Android帧动画
    AlertDialog之常见对话框(单选对话框、多选对话框、进度条对话框)
    BroadcastReceiver之(手动代码注册广播)屏幕锁屏、解锁监听、开机自启
    BroadcastReceiver之有序广播
    [FJOI2015]火星商店问题
  • 原文地址:https://www.cnblogs.com/semon-code/p/8231041.html
Copyright © 2020-2023  润新知