目录
今天上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中不可变数据类型和可变数据类型
数据类型 不可变数据类型/可变数据类型 整型 不可变数据类型 字符串 不可变数据类型 元组 不可变数据类型 列表 可变数据类型 集合 可变数据类型 字典 可变数据类型 2、Python中赋值、浅拷贝、深拷贝
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“赋值”、“浅拷贝”、“深拷贝”这三个知识点讲解的十分详细!
赋值
直接赋值的方式没有生产新的对象,只是新增了一个对象引用,即把地址全部赋值了一遍
浅拷贝
对于引用类型和包装类成员变量全部都是拷贝地址,并不会拷贝内容(值),对于值类型成员(int、char等)是直接拷贝内容(值)
深拷贝
对于值类型、引用类型、包装类型全部都是把内容(值)给拷贝一遍