最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

    正文概述 掘金(阿亮亮亮_)   2020-11-23   290

    Python中的深浅拷贝

    在讲深浅拷贝之前,我们先重温一下 is==的区别。

    在判断对象是否相等比较的时候我们可以用is==

    • is:比较两个对象的引用是否相同,即 它们的id 是否一样
    • == : 比较两个对象的值是否相同。

    如下

    天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

    首先,会为整数1分配一个内存空间。 变量a 和 b 都指向了这个内存空间(内存地址相等),所以他们的id相等。

    a is bTrue

    但是,真的所有整数数字都这样吗? 答案是:不是! 只有在 -25 ~ 256范围中的整数才不会重新分配内存空间。

    如下所示:

    因为257 超出了范围,所以id不相同,所以a is b返回的值为False。

    天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

    >>> a = 257
    >>> b = 257
    >>> print(id(a))
    20004752
    >>> print(id(b))
    20001312
    >>> print(a is b)
    False
    >>> print(a == b)
    True
    

    这样做是考虑到性能,Python对-5 到 256 的整数维护了一个数组,相当于一个缓存, 当数值在这个范围内,直接就从数组中返回相对应的引用地址了。如果不在这个范围内,会重新开辟一个新的内存空间。

    is 和 == 哪个效率高?

    相比之下,is比较的效率更高,因为它只需要判断两个对象的id是否相同即可。

    == 则需要重载__eq__ 这个函数,遍历变量中的所有元素内容,逐次比较是否相同。因此效率较低

    浅拷贝 深拷贝

    给变量进行赋值,有两种方法 直接赋值,拷贝

    直接赋值就 = 就可以了。而拷贝又分为浅拷贝和深拷贝

    先说结论吧:

    • 浅拷贝:拷贝的是对象的引用,如果原对象改变,相应的拷贝对象也会发生改变
    • 深拷贝:拷贝对象中的每个元素,拷贝对象和原有对象不在有关系,两个是独立的对象

    光看上面的概念,对新手来讲可能不太好理解。来看下面的例子吧

    赋值

    a = [1, 2, 3]
    b = a
    print(id(a)) # 52531048
    print(id(b)) # 52531048
    

    定义变量a,同时将a赋值给b。打印之后发现他们的id是相同的。说明指向了同一个内存地址。

    天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

    然后修改a的值,再查看他们的id

    a = [1, 2, 3]
    b = a
    print(id(a))  # 46169960
    a[1] = 0
    print(a, b)  # [1, 0, 3] [1, 0, 3]
    print(id(a))  # 46169960
    print(id(b))  # 46169960
    

    这时候发现修改后的a和b以及最开始的a的内存地址是一样的。也就是说a和b还是指向了那一块内存,只不过内存里面的[1, 2, 3] 变成了[1, 0, 3]

    所以我们就可以判断出,b和a的引用是相同的,当a发生改变的时候,b也会发生改变。

    天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

    赋值就是:你a无论怎么变,你指向谁,我b就跟着你指向谁。

    拷贝

    提到拷贝就避免不了可变对象和不可变对象。

    天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

    • **可变对象:**当有需要改变对象内部的值的时候,这个对象的id不发生变化。

    • **不可变对象:**当有需要改变对象内部的值的时候,这个对象的id会发生变化。

    a = [1, 2, 3]
    print(id(a)) # 56082504
    a.append(4)
    # 修改列表a之后 id没发生改变,可变对象
    print(id(a)) # 56082504
    
    a = 'hello'
    print(id(a)) # 59817760
    a = a + ' world'
    print(id(a)) # 57880072
    # 修改字符串a之后,id发生了变化。不可变对象
    print(a) # hello world
    

    浅拷贝

    拷贝的是不可变对象,**一定程度上来讲等同于赋值操作。**但是对于多层嵌套结构,浅拷贝只拷贝父对象,不拷贝内部的子对象。

    使用copy模块的 copy.copy 进行浅拷贝。

    import copy
    a = [1, 2, 3]
    b = copy.copy(a)
    print(id(a))  # 55755880
    print(id(b))  # 55737992
    a[1] = 0
    print(a, b) # [1, 0, 3] [1, 2, 3]
    

    通俗的讲,我将现在的a 复制一份重新分配了一个内存空间。后面你a怎么改变,那跟我b是没有任何关系的。 天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

    对于列表的浅拷贝还可以通过list(), list[:] 来实现

    但是!我前面提到了对于多层嵌套的结构,需要注意

    看下面的例子

    import copy
    a = [1, 2, [3, 4]]
    b = copy.copy(a)
    
    print(id(a)) # 23967528
    print(id(b)) # 21738984
    # 改变a中的子列表
    a[-1].append(5)
    print(a) # [1, 2, [3, 4, 5]]
    print(b) # [1, 2, [3, 4, 5]]  ?? 为什么不是[1, 2, [3, 4]]呢?
    

    b是由a浅拷贝得到的。我修改了a中嵌套的列表,发现b也跟着修改了?

    如果还是不太理解,可以参考下图。LIST就是一个嵌套的子对象,指向了另外一个内存空间。所以浅拷贝只是拷贝了元素12 和子对象的引用!

    天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

    另外一种情况,如果嵌套的是一个元组呢?

    import copy
    a = [1, 2, (3, 4)]
    b = copy.copy(a)
    
    # 改变a中的元组
    a[-1] += (5,)
    print(a) # [1, 2, (3, 4, 5)]
    print(b) # [1, 2, (3, 4)]
    

    我们发现浅拷贝得来的b并没有发生改变。因为元组是不可变对象。改变了元组就会生成新的对象。b中的元组引用还是指向了旧的元组。

    深拷贝

    所谓深拷贝呢,就是重新分配一个内存空间(新对象),将原对象中的所有元素通过递归的方式进行拷贝到新对象中。

    在Python中 通过copy.deepcopy() 来实现深拷贝。

    天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

    import copy
    a = [1, 2, [3, 4]]
    b = copy.deepcopy(a)
    
    print(id(a)) # 66587176
    print(id(b)) # 66587688
    # 改变a中的可变对象
    a[-1].append(5)
    print(a) # [1, 2, [3, 4, 5]]
    print(b) # [1, 2, [3, 4]]  深拷贝之后字列表不会受原来的影响
    
    

    结语

    1、深浅拷贝都会对源对象进行复制,占用不同的内存空间

    2、如果源对象没有子目录,则浅拷贝只能拷贝父目录,改动子目录时会影响浅拷贝的对象

    3、列表的切片本质就是浅拷贝



    起源地下载网 » 天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元