zoukankan      html  css  js  c++  java
  • 深拷贝浅拷贝

    不可变对象:该对象所指向的内存中的值不能被改变,修改对象的值时,由于其指向的值不能被改变,因此实际上是在内存中重新开辟一个地址用来存储新的值,然后将对象指向这个新值。本质上是两个对象,赋值前后对象id发生了变化。python中的不可变对象包括:bool、int、str、float、tuple、frozenset、None。

    可变对象:该对象所指向的内存中的值可以被改变。变量(引用)的值发生改变时,实际上是其指向的值直接发生改变,没有开辟新的内存地址。python中的可变对象包括:list、dict、set

    浅拷贝:通常指构造一个新的集合对象,然后用原始对象中的找到的子对象的引用来填充它。浅层的复制只有一层深度,复制过程中不会递归,所以不会创建子对象本身的副本。

    案例1

    import copy
    lst = [[1,2],3,4]
    new3_lst = copy.copy(lst)
    print(id(lst), lst)  # 2027983558024 [[1, 2], 3, 4]
    print(id(new3_lst), new3_lst)  # 2027983557000 [[1, 2], 3, 4]
    ==>先打印一下刚复制出来的两个对象及内存编号
    print('-------------------')
    new3_lst[0][0] = 4
    print(id(lst),lst)   # 2027983558024 [[4, 2], 3, 4]
    print(id(new3_lst),new3_lst)  # 2027983557000 [[4, 2], 3, 4]
    ==>推出:改变拷贝对象的子对象的成员值,会同时影响原始对象和拷贝对象
    print('-------------------')
    new3_lst[2] = 0
    print(id(lst),lst)  # 2757271180296 [[4, 2], 3, 4]
    print(id(new3_lst),new3_lst)  # 2757271135560 [[4, 2], 3, 0]
    ==>推出:改变拷贝对象的第一层次的成员值,不会影响原始对象
    
    print('-------------------')
    lst[2] = 0
    print(id(lst),lst)  # 2757271180296 [[4, 2], 3, 0]
    print(id(new3_lst),new3_lst)  # 2757271135560 [[4, 2], 3, 0]
    print('-------------------')
    lst[0][0] = 9
    print(id(lst),lst)  # 2757271180296 [[9, 2], 3, 0]
    print(id(new3_lst),new3_lst)  # 2757271135560 [[9, 2], 3, 0]
    ==>推出:改变原始对象的成员或者子对象的成员值,拷贝对象的元素跟着改变
    """
    总结
    浅拷贝,改变原始对象的成员或者子对象的成员值,拷贝对象的元素跟着改变
           改变拷贝对象的子对象的成员值,会同时影响原始对象和拷贝对象
           改变拷贝对象的第一层次的成员值,不会影响原始对象
    """
    

    案例2

    # example 1
    lst = [[1,2],3,4]
    new2_lst = list(lst)
    print(id(lst))  # 2291852075656
    print(id(new2_lst))  # 2291852075656
    print('-------------------')
    new2_lst[0][0] = 40
    print(id(lst),lst)   # 2364733153992 [[40, 2], 3, 4]
    print(id(new2_lst),new2_lst)  # 2364736713480 [[40, 2], 3, 4]
    print('-------------------')
    new2_lst[2] = 40
    print(id(lst),lst)  # 2364733153992 [[40, 2], 3, 4]
    print(id(new2_lst),new2_lst)  # 2364736713480 [[40, 2], 3, 40]
    
    print('***********************')
    lst[0][1] = 20
    print(id(lst),lst)  # 2364733153992 [[40, 20], 3, 4]
    print(id(new2_lst),new2_lst)  # 2364736713480 [[40, 20], 3, 40]
    print('-------------------')
    lst[2] = 30
    print(id(lst),lst)  # 2364733153992 [[40, 20], 3, 30]
    print(id(new2_lst),new2_lst)  # 2364736713480 [[40, 20], 3, 40]
    """
    总结
    修改第一层次的成员值,不会影响拷贝对象;修改子对象的成员值(第二层次),会同时影响原始对象和拷贝对象
    """
    

    深拷贝:深拷贝使复制过程递归,即首先构造一个新的集合对象,然后递归地用在原始对象中找到的子对象的副本来填充它。通过深拷贝复制对象,是原始对象及其所有子对象的完全独立的克隆。

    # 深拷贝: 拷贝对象及子对象(递归)
    lst1 = [[1,2],3,4]
    print('--------深拷贝--------')
    import copy
    new4_lst = copy.deepcopy(lst1)
    print(id(lst1),lst1)  # 1951550628552 [[1, 2], 3, 4]
    print(id(new4_lst),new4_lst)  # 1951582564552 [[1, 2], 3, 4]
    ==>先打印一下刚深拷贝出来的两个对象及内存编号
    print('-------------------')
    # 改变新对象的子对象的成员值,不会影响原始对象
    new4_lst[0][1] = 9
    print(id(lst1),lst1)  # 1951550628552 [[1, 2], 3, 4]
    print(id(new4_lst),new4_lst)  # 1951582564552 [[1, 9], 3, 4]
    
    print('-------------------')
    # 改变拷贝对象的第一层次的成员值,不会影响原始对象
    new4_lst[1] = 10
    print(id(lst1),lst1)  # 1951550628552 [[1, 2], 3, 4]
    print(id(new4_lst),new4_lst)  # 1951582564552 [[1, 9], 10, 4]
    
    print('-------------------')
    # 改变原始对象的子对象的成员值,不会影响拷贝对象
    lst1[0][1] = 20
    print(id(lst1),lst1)  # 1951550628552 [[1, 20], 3, 4]
    print(id(new4_lst),new4_lst)  # 1951582564552 [[1, 9], 10, 4]
    
    print('-------------------')
    # 改变原始对象的第一层次的成员值,不会影响拷贝对象
    lst1[1] = 16
    print(id(lst1),lst1)   # 1951550628552 [[1, 20], 16, 4]
    print(id(new4_lst),new4_lst)  # 1951582564552 [[1, 9], 10, 4]
    
    """
    总结
    深拷贝,新旧对像及其子对象的成员值完全独立,互不影响
    """
    

    总结

    • 不可变对象没有深拷贝和浅拷贝之分,可以理解为都是深拷贝
    • 创建对象的浅拷贝不会克隆子对象,不能完全对立与原始对象
    • 深拷贝会递归克隆原始对象,两者完全独立,互不影响,创建深拷贝的速度较慢
    更多学习笔记移步 https://www.cnblogs.com/kknote
  • 相关阅读:
    通过Jenkins调用自动部署war包及jar包到服务器上的Shell脚本
    CentOS7.3+MySQL5.7+Apache2.4+PHP7.1+phpMyAdmin4.7+JDK1.8+SVN1.6+Jenkins2.1环境搭建
    telegraf1.8+influxdb1.6+grafana5.2 环境搭建 结合JMeter3.2
    HttpRunner环境搭建
    Jenkins中启动从节点时,出现问题如何解决,问题:No Known Hosts...
    python读xml文件
    使用poi或jxl,通过java读写xls、xlsx文档
    编写生成32位大写和小写字符的md5的函数
    将一个字符与对应Ascii码互转
    生成随机删除的航班信息
  • 原文地址:https://www.cnblogs.com/kknote/p/13296776.html
Copyright © 2011-2022 走看看