• python学习之深浅拷贝


    4.2 深浅拷贝

    4.2.1 认识

    首先应该知道python中变量在内存中是怎么存放的!

    在python中,变量与变量的值占用不同的内存。变量占用的内存,并非直接存储数值,而存储的是值在内存中的地址。

    各种变量在内存中的存储,如下图:

    下面进行代码测试:

    ls = ['德玛','皇子','赵信']
    ls1 = ls           #ls1 = ls 实际上是ls1指向了ls指向的地址块,两者指向的是同一块地址区域,不是拷贝
    print(ls1)         #输出ls = ['德玛','皇子','赵信']
    ls.append('女警')   #对ls进行元素操作时,也是对ls1造成影响
    print(ls1)         #输出['德玛', '皇子', '赵信', '女警']
    ls2 = ls[:]        #利用切片,在内存中新建了一个列表,ls2指向这个新的列表,浅拷贝
    print(ls2)         #输出ls = ['德玛','皇子','赵信']
    ls.append('剑豪')   #对ls的元素进行任何操作,都不会影响ls2的内容
    print(ls2)          #输出ls = ['德玛','皇子','赵信']
    

    注意: a = 1 b= a 这不是拷贝,赋值是多个变量指向同一个内存地址,内存的任一元素改变,所有变量都受影响;

    ​ a = [1,2,3,4] b=a[:] 这是切片,切片是得到了一个新的列表,属于浅拷贝。

    4.2.2 浅拷贝.copy

    对只有一层元素关系的列表进行测试:

    ls = ['德玛','皇子','赵信']
    ls1 = ls.copy()
    print(id(ls),id(ls1))    #输出  2551633171528 2551633985416,可见二者指向的内存地址不同
    ls.append('剑豪')
    ls1.append('女警')
    print(ls)            #输出 ['德玛', '皇子', '赵信', '剑豪'],对ls的append操作没有影响ls1
    print(ls1)			#输出 ['德玛', '皇子', '赵信', '女警'],对ls1的append操作没有影响ls
    ls.pop(ls[0])
    

    从以上结果可得:在copy完之后,新的列表指向新的内存地址,分别对列表的最后一位进行appen操作,结果互不影响。

    对具有二层的元素的列表进行测试:

    ##对ls的第二个元素进行append操作
    ls = ['德玛',['费欧娜','戴安娜'],'赵信']
    ls1 = ls.copy()             
    print(ls1)				    #输出['德玛', ['费欧娜', '戴安娜'], '赵信']
    ls[1].append('莫甘娜')       #copy完成后对ls的第二个元素进行append操作
    print(ls1)           #输出'德玛', ['费欧娜', '戴安娜', '莫甘娜'], '赵信'],ls1发生了改变
    print(id(ls[1]),id(ls1[1]))  #查看两者的ID,2202073060424 2202073060424
    
    ##对ls1的第二个元素进行操作
    ls = ['德玛',['费欧娜','戴安娜'],'赵信']
    ls1 = ls.copy()
    print(ls)			    #输出['德玛', ['费欧娜', '戴安娜'], '赵信']
    ls1[1].append('莫甘娜')	#copy完成后对ls1的第二个元素进行append操作
    print(ls)			#输出'德玛', ['费欧娜', '戴安娜', '莫甘娜'], '赵信'],ls发生了改变
    print(id(ls[1]),id(ls1[1]))  #输出 2303581443144 2303581443144
    

    从上边输出的结果来看,copy完成之后,分别对ls和ls1的中间元素进行append操作,对方的元素也会发生相应的改变。

    结论:浅拷⻉, 只会拷⻉第⼀层内容,只拷贝第二层关系的内存地址,而第⼆层的内容不会拷贝,所以被称为浅拷贝。

    4.2.3 深拷贝.deepcopy()

    深拷贝使用之前一定要先加载copy模块,import copy

    语法为:

    import copy

    new_ls = copy.deepcopy(ls)

    #对ls进行二层操作
    import copy
    ls = ['德玛',['费欧娜','戴安娜'],'赵信']
    ls1 = copy.deepcopy(ls)
    ls[1].append('莫甘娜')
    print(ls)                 #输出['德玛', ['费欧娜', '戴安娜', '莫甘娜'], '赵信']
    print(ls1)				 #输出['德玛', ['费欧娜', '戴安娜'], '赵信']
    
    #对ls1进行二层操作
    import copy
    ls = ['德玛',['费欧娜','戴安娜'],'赵信']
    ls1 = copy.deepcopy(ls)
    ls1[1].append('莫甘娜')
    print(ls)				#输出['德玛', ['费欧娜', '戴安娜'], '赵信']
    print(ls1)				#输出['德玛', ['费欧娜', '戴安娜', '莫甘娜'], '赵信']
    

    由以上结果可得:深拷贝是完完全全的复制,是创建一个完完全全的新的对象,新旧对象之间不会相互影响。不可变数据类型新旧列表指向同一个空间,可变类型新列表创建了新的空间

    【注意:】

    a = [1, 2]
    a[1] = a   #对a列表的第二个元素进行修改成自己
    print(a[1])  #输出为[1, [...]]
    print(id(a),id(a[1]))  #输出内存地址1191853053000 1191853053000  a与a[1]的内存地址一样
    print(type(a[1]))  ##输出<class 'list'>
    

    分析: a[1] 原来是int类型,在对a[1]进行修改操作时,会先把原来的指向剪断,因为赋值a,指向了自己,此时出现了数据上的死循环

    仅供参考,欢迎指正
  • 相关阅读:
    php 克隆和引用类
    php 抽象类、接口和构析方法
    php 面向对象之继承、多态和静态方法
    php封装练习
    php 面向对象之封装
    php 简单操作数据库
    php 练习
    用php输入表格内容
    php 指针遍历、预定义数组和常用函数
    php 数组定义、取值和遍历
  • 原文地址:https://www.cnblogs.com/jjzz1234/p/11027414.html
Copyright © 2020-2023  润新知