Python中如何理解浅拷贝、深拷贝和赋值

目录

Python部分

赋值

浅拷贝

深拷贝

Tips

Python总结

Java部分

代码:

赋值

浅拷贝

深拷贝


今天上Python课解决了一个关于列表中“深拷贝、浅拷贝、赋值”的问题,这里做一个分享!

Python部分

Python中也分“赋值”、“浅拷贝”、“深拷贝”,废话不多说直接上代码!

import copy

#打印函数
def pt(n):
    print("id(n)的地址:"+str(id(n)))
    print("id(n[0])的地址:"+str(id(n[0])))
    print("id(n[1])的地址:"+str(id(n[1])))
    print("id(n[2])的地址:"+str(id(n[2])))
    print("id(n[2][0])的地址:"+str(id(n[2][0])))
    print("id(n[2][1])的地址:" + str(id(n[2][1])))
    print("id(n[2][0][0])的地址:" + str(id(n[2][0][0])))
    print("id(n[2][0][1])的地址:" + str(id(n[2][0][1])))

a=[1,2,[[3,4],5]]
print("\n==== 原始地址:a的地址 ===")
pt(a)
##1、直接赋值是别名
print("\n==== 直接赋值:b的地址 ===")
b=a;
pt(b)
##2、浅拷贝
print("\n==== 浅拷贝:c的地址 ===")
c=a[:]
pt(c)
##3、深拷贝
print("\n==== 深拷贝:d的地址 ===")
d=copy.deepcopy(a)
pt(d)

原地址:

a=[1,2,[[3,4],5]]
print("\n==== 原始地址:a的地址 ===")
pt(a)

首先我们来看一下原始a列表中的每一个元素的地址:

赋值

##1、直接赋值是别名
print("\n==== 直接赋值:b的地址 ===")
b=a;
pt(b)

  • 将a直接赋值给b后观察b中每一个元素的地址
  • 对比发现所有对应元素的地址都未发生改变
  • 不难得出赋值操作只是把所有的地址都给拷贝了一遍

浅拷贝

##2、浅拷贝
print("\n==== 浅拷贝:c的地址 ===")
c=a[:]
pt(c)

  • 将a的切片赋值给c后观察c中每一个元素的地址
  • 对比发现只有最外层的壳子地址发生变化,其它的所有元素的地址都相同
  • 不难得出浅拷贝操作其实只是换了一个最外层的壳子,其内部所有元素的地址和内部的壳子地址都未发生变化

深拷贝

##3、深拷贝
print("\n==== 深拷贝:d的地址 ===")
d=copy.deepcopy(a)
pt(d)

  • 将a的深拷贝给d后观察d中每一个元素的地址
  • 对比发现所有的壳子地址都发生了变化,其它的所有基本元素的地址都未发生变化
  • 不难得出深拷贝操作其实是把所有的壳子都给换了一遍,其内部的基本元素的地址都未发生变化

示意图:

小Tips:

上面仅针对Python中列表的深拷贝、浅拷贝、赋值,列表是属于可变数据类型,当遇到不可变数据类型,例如:元组,又是另外一种情况,下篇博客讲解的非常详细!

参考博客:

1、Python中不可变数据类型和可变数据类型

python中不可变数据类型和可变数据类型_Python热爱者的博客-CSDN博客_python中可变数据类型与不可变数据类型在学习python过程中我们一定会遇到不可变数据类型和可变数据类型。1.名词解释以下所有的内容都是基于内存地址来说的。不可变数据类型: 当该数据类型的对应变量的值发生了改变,那么它对应的内存地址也会发生改变,对于这种数据类型,就称不可变数据类型。可变数据类型 :当该数据类型的对应变量的值发生了改变,那么它对应的内存地址不发生改变,对于这种数据类型,就称可变数据类型。总结:不可变数据类型更改后地址发生改变,可变数据类型更改地址不发生改变2.数据类型分类在python中数据类型有https://blog.csdn.net/qdPython/article/details/114838276

数据类型不可变数据类型/可变数据类型
整型不可变数据类型
字符串不可变数据类型
元组不可变数据类型
列表可变数据类型
集合可变数据类型
字典可变数据类型

2、Python中赋值、浅拷贝、深拷贝

Python中的浅拷贝和深拷贝(一看就懂!!!)_时代&信念的博客-CSDN博客_python浅拷贝与深拷贝浅拷贝和深拷贝一直傻傻的分不清,甚至有时候会理解反。今天就简单总结一下python中的浅拷贝和深拷贝。最直观的理解就是:1.深拷贝,拷贝的程度深,自己新开辟了一块内存,将被拷贝内容全部拷贝过来了;2.浅拷贝,拷贝的程度浅,只拷贝原数据的首地址,然后通过原数据的首地址,去获取内容。两者的优缺点对比:(1)深拷贝拷贝程度高,将原数据复制到新的内存空间中。改变拷贝后的内容不影响原数据内容。但是深拷贝耗时长,且占用内存空间。(2)浅拷贝拷贝程度低,只复制原数据的地址。其实是将副本的地址指向原数据地址。修改https://blog.csdn.net/Elon15/article/details/125256787?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-125256787-blog-119278072.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-125256787-blog-119278072.pc_relevant_aa&utm_relevant_index=1

Python总结

深拷贝

  • 当内层为可变数据类型时,深拷贝内层外层地址均发生改变
  • 当内层为不可变数据类型时,外层不管是可变还是不可变数据类型,使用深拷贝都不会改变内层地址,其中如果外层为可变数据类型改变外层地址

浅拷贝

  • 外层地址,只能在外层数据类型为可变数据类型时,才能改变外层地址
  • 内层地址,无论是否为可变数据类型还是不可变数据类型,使用浅拷贝都不会改变内层数据类型地址。
     

Java部分

在我原有的印象中只有“浅拷贝”和“深拷贝”并没有“第三者”赋值这么一说,我默认的把赋值直接归为“浅拷贝”,我印象中在Java里赋值就算是浅拷贝,刚刚试了一下Java直接赋值,然后查了一下相关博客,发现Java也是把赋值、深拷贝、浅拷贝这三者给区分开的!!

下图是验证Java赋值操作:

代码:

package 草稿;

import java.util.Arrays;

/**
 * @author yx
 * @date 2022-09-03 16:49
 */
public class example {
    public String toString() {
        return "InfiniteRecursive address: " + super.toString() + "\n";
    }
    public static void main(String[] args) {
        example ir = new example();
        example br=ir;
        System.out.println(ir);
        System.out.println(br);
    }
}

参考文章:这篇文章关于Java“赋值”、“浅拷贝”、“深拷贝”这三个知识点讲解的十分详细!

Java拷贝(赋值、浅拷贝、深拷贝)_翻滚de蛋炒饭的博客-CSDN博客_java赋值是深拷贝还是浅拷贝文章目录拷贝直接赋值浅拷贝实现方式特殊情况深拷贝实现方式多层克隆拷贝直接赋值直接赋值的方式没有生产新的对象,只是生新增了一个对象引用浅拷贝如果原型对象的成员变量是值类型,将复制一份给克隆对象,也就是说在堆中拥有独立的空间;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。换句话说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。实现方式被复制类需要实现https://blog.csdn.net/qq_36739040/article/details/115472533?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166598044716800186513873%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=166598044716800186513873&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-115472533-null-null.142%5Ev58%5Econtrol_1,201%5Ev3%5Eadd_ask&utm_term=Java%E4%B8%AD%E7%9A%84%E8%B5%8B%E5%80%BC%E6%93%8D%E4%BD%9C%E6%98%AF%E4%BB%80%E4%B9%88%E6%8B%B7%E8%B4%9D&spm=1018.2226.3001.4187将文章中的内容总结如下:

赋值

直接赋值的方式没有生产新的对象,只是新增了一个对象引用,即把地址全部赋值了一遍

浅拷贝

对于引用类型和包装类成员变量全部都是拷贝地址,并不会拷贝内容(值),对于值类型成员(int、char等)是直接拷贝内容(值)

深拷贝

对于值类型、引用类型、包装类型全部都是把内容(值)给拷贝一遍

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小羊不会飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值